feat(theme): 购买主题后自动写入用户主题表

This commit is contained in:
2025-12-11 14:23:52 +08:00
parent 262c822585
commit f937b03940
11 changed files with 221 additions and 5 deletions

View File

@@ -0,0 +1,12 @@
package com.yolo.keyborad.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yolo.keyborad.model.entity.KeyboardUserThemes;
/*
* @author: ziin
* @date: 2025/12/11 13:31
*/
public interface KeyboardUserThemesMapper extends BaseMapper<KeyboardUserThemes> {
}

View File

@@ -8,6 +8,8 @@ import com.yolo.keyborad.typehandler.StringArrayTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import lombok.Data;
/*
@@ -31,9 +33,9 @@ public class KeyboardThemes {
@Schema(description="键盘价格")
private BigDecimal themePrice;
@TableField(value = "theme_tag", typeHandler = StringArrayTypeHandler.class)
@TableField(value = "theme_tag")
@Schema(description="主题标签")
private String[] themeTag;
private List<ThemeTagItem> themeTag;
@TableField(value = "theme_download")
@Schema(description="主题下载次数")

View File

@@ -0,0 +1,61 @@
package com.yolo.keyborad.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Date;
import lombok.Data;
/*
* @author: ziin
* @date: 2025/12/11 13:31
*/
@Schema
@Data
@TableName(value = "keyboard_user_themes")
public class KeyboardUserThemes {
/**
* 主键 id
*/
@TableId(value = "id", type = IdType.AUTO)
@Schema(description="主键 id")
private Long id;
/**
* 主题主键
*/
@TableField(value = "theme_id")
@Schema(description="主题主键")
private Long themeId;
/**
* 用户 Id
*/
@TableField(value = "user_id")
@Schema(description="用户 Id")
private Long userId;
/**
* 创建时间
*/
@TableField(value = "created_at")
@Schema(description="创建时间")
private Date createdAt;
/**
* 是否从显示移除
*/
@TableField(value = "view_deleted")
@Schema(description="是否从显示移除")
private Boolean viewDeleted;
/**
* 更新时间
*/
@TableField(value = "updated_at")
@Schema(description="更新时间")
private Boolean updatedAt;
}

View File

@@ -0,0 +1,10 @@
package com.yolo.keyborad.model.entity;
import lombok.Data;
// ThemeTagItem.java
@Data
public class ThemeTagItem {
private String label;
private String color;
}

View File

@@ -1,9 +1,11 @@
package com.yolo.keyborad.model.vo.themes;
import com.yolo.keyborad.model.entity.ThemeTagItem;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/*
* @author: ziin
@@ -34,7 +36,7 @@ public class KeyboardThemesRespVO {
* 主题标签
*/
@Schema(description = "主题标签")
private String[] themeTag;
private List<ThemeTagItem> themeTag;
/**
* 主题下载次数

View File

@@ -0,0 +1,13 @@
package com.yolo.keyborad.service;
import com.yolo.keyborad.model.entity.KeyboardUserThemes;
import com.baomidou.mybatisplus.extension.service.IService;
/*
* @author: ziin
* @date: 2025/12/11 13:31
*/
public interface KeyboardUserThemesService extends IService<KeyboardUserThemes>{
}

View File

@@ -3,12 +3,14 @@ package com.yolo.keyborad.service.impl;
import com.yolo.keyborad.common.ErrorCode;
import com.yolo.keyborad.exception.BusinessException;
import com.yolo.keyborad.model.entity.KeyboardThemes;
import com.yolo.keyborad.model.entity.KeyboardUserThemes;
import com.yolo.keyborad.model.entity.KeyboardUserWallet;
import com.yolo.keyborad.model.entity.KeyboardWalletTransaction;
import com.yolo.keyborad.model.vo.purchase.ThemePurchaseListRespVO;
import com.yolo.keyborad.model.vo.purchase.ThemePurchaseRespVO;
import com.yolo.keyborad.model.vo.themes.KeyboardThemesRespVO;
import com.yolo.keyborad.service.KeyboardThemesService;
import com.yolo.keyborad.service.KeyboardUserThemesService;
import com.yolo.keyborad.service.KeyboardUserWalletService;
import com.yolo.keyborad.service.KeyboardWalletTransactionService;
import jakarta.annotation.Resource;
@@ -42,6 +44,9 @@ public class KeyboardThemePurchaseServiceImpl extends ServiceImpl<KeyboardThemeP
@Resource
private KeyboardWalletTransactionService transactionService;
@Resource
private KeyboardUserThemesService userThemesService;
@Override
@Transactional(rollbackFor = Exception.class)
public ThemePurchaseRespVO purchaseTheme(Long userId, Long themeId) {
@@ -135,7 +140,15 @@ public class KeyboardThemePurchaseServiceImpl extends ServiceImpl<KeyboardThemeP
purchase.setWalletTxId(transaction.getId());
this.updateById(purchase);
// 9. 构造返回结果
// 9. 添加到用户主题表
KeyboardUserThemes userTheme = new KeyboardUserThemes();
userTheme.setUserId(userId);
userTheme.setThemeId(themeId);
userTheme.setCreatedAt(new Date());
userTheme.setViewDeleted(false);
userThemesService.save(userTheme);
// 10. 构造返回结果
// 创建响应对象,封装购买结果信息
ThemePurchaseRespVO respVO = new ThemePurchaseRespVO();
respVO.setOrderNo(orderNo); // 订单号

View File

@@ -0,0 +1,18 @@
package com.yolo.keyborad.service.impl;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yolo.keyborad.model.entity.KeyboardUserThemes;
import com.yolo.keyborad.mapper.KeyboardUserThemesMapper;
import com.yolo.keyborad.service.KeyboardUserThemesService;
/*
* @author: ziin
* @date: 2025/12/11 13:31
*/
@Service
public class KeyboardUserThemesServiceImpl extends ServiceImpl<KeyboardUserThemesMapper, KeyboardUserThemes> implements KeyboardUserThemesService{
}

View File

@@ -0,0 +1,67 @@
// ThemeTagTypeHandler.java
package com.yolo.keyborad.typehandler;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yolo.keyborad.model.entity.ThemeTagItem;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;
import org.postgresql.util.PGobject;
import java.sql.*;
import java.util.List;
@MappedTypes(List.class)
@MappedJdbcTypes(JdbcType.OTHER) // PostgreSQL jsonb = OTHER
public class ThemeTagTypeHandler extends BaseTypeHandler<List<ThemeTagItem>> {
private static final ObjectMapper MAPPER = new ObjectMapper();
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
List<ThemeTagItem> parameter,
JdbcType jdbcType) throws SQLException {
try {
String json = MAPPER.writeValueAsString(parameter);
PGobject pgObject = new PGobject();
pgObject.setType("jsonb");
pgObject.setValue(json);
ps.setObject(i, pgObject);
} catch (Exception e) {
throw new SQLException("Failed to convert themeTag to jsonb", e);
}
}
@Override
public List<ThemeTagItem> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
return parseJson(json);
}
@Override
public List<ThemeTagItem> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
return parseJson(json);
}
@Override
public List<ThemeTagItem> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
return parseJson(json);
}
private List<ThemeTagItem> parseJson(String json) throws SQLException {
if (json == null) {
return null;
}
try {
return MAPPER.readValue(json, new TypeReference<List<ThemeTagItem>>() {});
} catch (Exception e) {
throw new SQLException("Failed to parse jsonb to List<ThemeTagItem>: " + json, e);
}
}
}

View File

@@ -7,7 +7,7 @@
<id column="id" jdbcType="BIGINT" property="id" />
<result column="theme_name" jdbcType="VARCHAR" property="themeName" />
<result column="theme_price" jdbcType="NUMERIC" property="themePrice" />
<result column="theme_tag" jdbcType="ARRAY" property="themeTag" typeHandler="com.yolo.keyborad.typehandler.StringArrayTypeHandler" />
<result column="theme_tag" jdbcType="VARCHAR" property="themeTag"/>
<result column="theme_download" jdbcType="VARCHAR" property="themeDownload" />
<result column="theme_style" jdbcType="BIGINT" property="themeStyle" />
<result column="theme_status" jdbcType="BOOLEAN" property="themeStatus" />

View File

@@ -0,0 +1,18 @@
<?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.yolo.keyborad.mapper.KeyboardUserThemesMapper">
<resultMap id="BaseResultMap" type="com.yolo.keyborad.model.entity.KeyboardUserThemes">
<!--@mbg.generated-->
<!--@Table keyboard_user_themes-->
<id column="id" jdbcType="BIGINT" property="id" />
<result column="theme_id" jdbcType="BIGINT" property="themeId" />
<result column="user_id" jdbcType="BIGINT" property="userId" />
<result column="created_at" jdbcType="TIMESTAMP" property="createdAt" />
<result column="view_deleted" jdbcType="BOOLEAN" property="viewDeleted" />
<result column="updated_at" jdbcType="BOOLEAN" property="updatedAt" />
</resultMap>
<sql id="Base_Column_List">
<!--@mbg.generated-->
id, theme_id, user_id, created_at, view_deleted, updated_at
</sql>
</mapper>