feat(game): 新增平台管理功能

- 添加平台管理相关的实体类、Mapper、Service及其实现类
- 实现平台信息的缓存加载和获取
- 新增美天棋牌平台的支持
-重构原有的地址源获取逻辑,使用平台代码进行配置
- 删除了未使用的旧代码和注释
main-meitian
liaoyong 2025-04-03 11:20:05 +08:00
parent 3b8cddd2ec
commit b7ff4ada0e
22 changed files with 552 additions and 139 deletions

View File

@ -92,6 +92,8 @@ public class CacheConstants {
*/ */
public static final String MeiTian_GAMES = "meitian_games:"; public static final String MeiTian_GAMES = "meitian_games:";
public static final String Platform = "platform:";
} }

View File

@ -11,23 +11,21 @@ public enum GamePlatforms {
FC("FC", "FC"), FC("FC", "FC"),
SA("SA", "SA"), SA("SA", "SA"),
DG("DG", "DG"), DG("DG", "DG"),
MeiTian("MeiTian","美天棋牌"), MT("MT", "美天棋牌"),
AE("AE", "AE"), AE("AE", "AE"),
; ;
private final String code; private final String code;
private final String info; private final String info;
GamePlatforms(String code, String info) GamePlatforms(String code, String info) {
{
this.code = code; this.code = code;
this.info = info; this.info = info;
} }
public static List<String> getCodes() public static List<String> getCodes() {
{ List<String> result = new ArrayList<>();
List<String> result=new ArrayList<>();
GamePlatforms[] values = GamePlatforms.values(); GamePlatforms[] values = GamePlatforms.values();
for (GamePlatforms value : values) { for (GamePlatforms value : values) {
result.add(value.getCode()); result.add(value.getCode());
@ -35,13 +33,11 @@ public enum GamePlatforms {
return result; return result;
} }
public String getCode() public String getCode() {
{
return code; return code;
} }
public String getInfo() public String getInfo() {
{
return info; return info;
} }

View File

@ -21,7 +21,8 @@ public enum PlatformType {
VIDEO(6, "视讯"), VIDEO(6, "视讯"),
LOTTERY(7, "彩票"), LOTTERY(7, "彩票"),
SPORTS(8, "体育"), SPORTS(8, "体育"),
HUNTING(9, "捕猎"); HUNTING(9, "捕猎"),
BaiRen(10, "百人场");
private final int code; private final int code;
private final String name; private final String name;

View File

@ -0,0 +1,59 @@
package com.ff.base.handler;
import com.alibaba.fastjson2.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* mybatis json
*
* @author cengy
*/
public class JsonHandler<T> extends BaseTypeHandler<T> {
private final Class<T> type;
public JsonHandler(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public T getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
if (json != null) {
return JSON.parseObject(json, type);
}
return null;
}
@Override
public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
if (json != null) {
return JSON.parseObject(json, type);
}
return null;
}
@Override
public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
if (json != null) {
return JSON.parseObject(json, type);
}
return null;
}
}

View File

@ -0,0 +1,64 @@
package com.ff.base.handler;
import com.alibaba.fastjson2.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* mybatis json
*
* @author cengy
*/
public class JsonListHandler<T> extends BaseTypeHandler<List<T>> {
private final Class<T> type;
public JsonListHandler(Class<T> type) {
if (type == null) {
throw new IllegalArgumentException("Type argument cannot be null");
}
this.type = type;
}
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
// Convert the List<Item> to JSON string
String json = JSON.toJSONString(parameter);
ps.setString(i, json);
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
String json = rs.getString(columnName);
if (json == null) {
return null;
}
return JSON.parseArray(json, type);
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
String json = rs.getString(columnIndex);
if (json == null) {
return null;
}
return JSON.parseArray(json, type);
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
String json = cs.getString(columnIndex);
if (json == null) {
return null;
}
return JSON.parseArray(json, type);
}
}

View File

@ -4,7 +4,6 @@ import com.ff.base.constant.Constants;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import sun.misc.BASE64Encoder;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
@ -15,27 +14,23 @@ import java.security.NoSuchAlgorithmException;
* *
* @author ff * @author ff
*/ */
public class Md5Utils public class Md5Utils {
{
private static final Logger log = LoggerFactory.getLogger(Md5Utils.class); private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
private static byte[] md5(String s) private static byte[] md5(String s) {
{
MessageDigest algorithm; MessageDigest algorithm;
try try {
{
algorithm = MessageDigest.getInstance("MD5"); algorithm = MessageDigest.getInstance("MD5");
algorithm.reset(); algorithm.reset();
algorithm.update(s.getBytes("UTF-8")); algorithm.update(s.getBytes("UTF-8"));
byte[] messageDigest = algorithm.digest(); byte[] messageDigest = algorithm.digest();
return messageDigest; return messageDigest;
} } catch (Exception e) {
catch (Exception e)
{
log.error("MD5 Error...", e); log.error("MD5 Error...", e);
} }
return null; return null;
} }
public static String md5New(String input) { public static String md5New(String input) {
try { try {
MessageDigest md = MessageDigest.getInstance("MD5"); MessageDigest md = MessageDigest.getInstance("MD5");
@ -63,30 +58,24 @@ public class Md5Utils
return null; return null;
} }
String result = ""; String result = "";
try{ try {
MessageDigest md5 = MessageDigest.getInstance("MD5"); MessageDigest md5 = MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder(); result = Base64.encode(md5.digest(str.getBytes(StandardCharsets.UTF_8)));
result = base64en.encode(md5.digest(str.getBytes(StandardCharsets.UTF_8))); } catch (Exception e) {
}catch (Exception e){ log.error("encoderByMd5...{}", str, e);
log.error("encoderByMd5...{0}", str, e);
} }
return result; return result;
} }
private static final String toHex(byte hash[]) private static final String toHex(byte hash[]) {
{ if (hash == null) {
if (hash == null)
{
return null; return null;
} }
StringBuffer buf = new StringBuffer(hash.length * 2); StringBuffer buf = new StringBuffer(hash.length * 2);
int i; int i;
for (i = 0; i < hash.length; i++) for (i = 0; i < hash.length; i++) {
{ if ((hash[i] & 0xff) < 0x10) {
if ((hash[i] & 0xff) < 0x10)
{
buf.append("0"); buf.append("0");
} }
buf.append(Long.toString(hash[i] & 0xff, 16)); buf.append(Long.toString(hash[i] & 0xff, 16));
@ -94,15 +83,11 @@ public class Md5Utils
return buf.toString(); return buf.toString();
} }
public static String hash(String s) public static String hash(String s) {
{ try {
try return new String(toHex(md5(Constants.PASS_PREFIX + s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
{ } catch (Exception e) {
return new String(toHex(md5(Constants.PASS_PREFIX +s)).getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8); log.error("not supported charset...", e);
}
catch (Exception e)
{
log.error("not supported charset...{}", e);
return s; return s;
} }
} }

View File

@ -16,7 +16,6 @@
<dependencies> <dependencies>
<!-- spring-boot-devtools --> <!-- spring-boot-devtools -->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -5,6 +5,7 @@ import com.ff.base.system.domain.SysDatasource;
import com.ff.base.system.mapper.SysDatasourceMapper; import com.ff.base.system.mapper.SysDatasourceMapper;
import com.ff.base.system.service.ISysConfigService; import com.ff.base.system.service.ISysConfigService;
import com.ff.base.system.service.ISysDictTypeService; import com.ff.base.system.service.ISysDictTypeService;
import com.ff.game.service.IPlatformService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
@ -34,6 +35,9 @@ public class ContentRefreshedEventListener implements ApplicationListener<Contex
@Resource @Resource
private ISysDictTypeService sysDictTypeService; private ISysDictTypeService sysDictTypeService;
@Resource
private IPlatformService platformService;
/** /**
* *
* *
@ -50,5 +54,7 @@ public class ContentRefreshedEventListener implements ApplicationListener<Contex
} }
sysConfigService.loadingConfigCache(); sysConfigService.loadingConfigCache();
sysDictTypeService.loadingDictCache(); sysDictTypeService.loadingDictCache();
platformService.loadToCache();
} }
} }

View File

@ -3,8 +3,8 @@ package com.ff.game.api.meitian.address;
import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.callback.AddressSource;
import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestAddress;
import com.dtflys.forest.http.ForestRequest; import com.dtflys.forest.http.ForestRequest;
import com.ff.base.constant.Constants; import com.ff.base.enums.GamePlatforms;
import com.ff.base.system.service.ISysConfigService; import com.ff.game.service.IPlatformService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -18,12 +18,12 @@ import javax.annotation.Resource;
public class MeiTianAddressSource implements AddressSource { public class MeiTianAddressSource implements AddressSource {
@Resource @Resource
private ISysConfigService configService; private IPlatformService platformService;
@Override @Override
public ForestAddress getAddress(ForestRequest request) { public ForestAddress getAddress(ForestRequest request) {
String apiBaseUrl = configService.selectConfigByKey(Constants.MEITIAN_API_BASE_URL); String apiBaseUrl = platformService.get(GamePlatforms.MT.getCode())
.getUrlInfo().getUrl();
return new ForestAddress("https", apiBaseUrl, 443, "services"); return new ForestAddress("https", apiBaseUrl, 443, "services");
} }
} }

View File

@ -1,89 +0,0 @@
package com.ff.game.api.meitian.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigDecimal;
/**
* JiLi
*
* @author shi
* @date 2024/10/21
*/
@NoArgsConstructor
@Data
public class JILIBetRecordDataResponseDTO {
/**
*
*/
@JsonProperty("Account")
private String account;
/**
* id
*/
@JsonProperty("WagersId")
private String wagersId;
/**
* id
*/
@JsonProperty("GameId")
private String gameId;
/**
*
*/
@JsonProperty("WagersTime")
private Long wagersTime;
/**
*
*/
@JsonProperty("BetAmount")
private BigDecimal betAmount;
/**
*
*/
@JsonProperty("PayoffTime")
private Long payoffTime;
/**
*
*/
@JsonProperty("PayoffAmount")
private BigDecimal payoffAmount;
/**
* 1: 2: 3:
*/
@JsonProperty("Status")
private int status;
/**
*
*/
@JsonProperty("SettlementTime")
private Long settlementTime;
/**
* id
*/
@JsonProperty("GameCategoryId")
private int gameCategoryId;
/**
*
*/
@JsonProperty("Type")
private int type;
/**
* id
*/
@JsonProperty("AgentId")
private String agentId;
/**
*
*/
@JsonProperty("Turnover")
private BigDecimal turnover;
/**
*
*/
@JsonProperty("RoundIndex")
private long roundIndex;
}

View File

@ -0,0 +1,10 @@
package com.ff.game.domain;
import java.io.Serializable;
import java.util.HashMap;
/**
* @author cengy
*/
public class CurrencyInfo extends HashMap<String, Object> implements Serializable {
}

View File

@ -0,0 +1,21 @@
package com.ff.game.domain;
import lombok.Data;
import java.io.Serializable;
/**
*
*
* @author cengy
*/
@Data
public class KeyInfo implements Serializable {
private String code;
private String key;
private String currency;
private String password;
private String providerCode;
}

View File

@ -0,0 +1,14 @@
package com.ff.game.domain;
import java.io.Serializable;
import java.util.HashMap;
/**
* @author cengy
*/
public class LangInfo extends HashMap<String, String> implements Serializable {
public String get(String lang) {
return super.get(lang);
}
}

View File

@ -0,0 +1,38 @@
package com.ff.game.domain;
import com.ff.base.core.domain.BaseEntity;
import lombok.Data;
import java.util.List;
/**
* @author cengy
*/
@Data
public class Platform extends BaseEntity {
/**
*
*/
private Integer sortNo;
/**
* code
*/
private String platformCode;
/**
*
*/
private String platformName;
/**
* true: false:
*/
private Boolean stopStatus;
private List<PlatformInfo> platformInfo;
private List<KeyInfo> keyInfo;
private LangInfo langInfo;
private CurrencyInfo currencyInfo;
private UrlInfo urlInfo;
}

View File

@ -0,0 +1,15 @@
package com.ff.game.domain;
import lombok.Data;
import java.io.Serializable;
/**
* @author cengy
*/
@Data
public class PlatformInfo implements Serializable {
private String code;
private String name;
private int type;
}

View File

@ -0,0 +1,16 @@
package com.ff.game.domain;
import lombok.Data;
import java.io.Serializable;
/**
* @author cengy
*/
@Data
public class UrlInfo implements Serializable {
private String url;
private String loginUrl;
private String hallCode;
}

View File

@ -0,0 +1,24 @@
package com.ff.game.mapper;
import com.ff.game.domain.Platform;
import java.util.List;
/**
* @author cengy
*/
public interface PlatformMapper {
List<Platform> selectList(Platform platform);
Platform selectByPlatformCode(String platformCode);
int updatePlatform(Platform platform);
int insertPlatform(Platform platform);
int deleteById(Long id);
int deleteByIds(String ids);
}

View File

@ -0,0 +1,27 @@
package com.ff.game.service;
import com.ff.game.domain.Platform;
import java.util.List;
/**
* @author cengy
*/
public interface IPlatformService {
List<Platform> selectList(Platform platform);
Platform selectByPlatformCode(String platformCode);
int updatePlatform(Platform platform);
int insertPlatform(Platform platform);
int deleteById(Long id);
int deleteByIds(String ids);
void loadToCache();
Platform get(String platformCode);
}

View File

@ -0,0 +1,79 @@
package com.ff.game.service.impl;
import com.ff.base.constant.CacheConstants;
import com.ff.base.core.redis.RedisCache;
import com.ff.base.datasource.DynamicDataSourceContextHolder;
import com.ff.game.domain.Platform;
import com.ff.game.mapper.PlatformMapper;
import com.ff.game.service.IPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;
/**
* @author cengy
*/
@Service
public class PlatformServiceImpl implements IPlatformService {
@Autowired
PlatformMapper platformMapper;
@Autowired
RedisCache redisCache;
@Override
public List<Platform> selectList(Platform platform) {
return platformMapper.selectList(platform);
}
@Override
public Platform selectByPlatformCode(String platformCode) {
return platformMapper.selectByPlatformCode(platformCode);
}
@Override
public int updatePlatform(Platform platform) {
return platformMapper.updatePlatform(platform);
}
@Override
public int insertPlatform(Platform platform) {
return platformMapper.insertPlatform(platform);
}
@Override
public int deleteById(Long id) {
return platformMapper.deleteById(id);
}
@Override
public int deleteByIds(String ids) {
return platformMapper.deleteByIds(ids);
}
@Override
public void loadToCache() {
Map<Object, DataSource> resolvedDataSources = DynamicDataSourceContextHolder.getAllDataSource();
for (Map.Entry<Object, DataSource> entry : resolvedDataSources.entrySet()) {
Object key = entry.getKey();
// 设置数据源类型
DynamicDataSourceContextHolder.setDataSourceType(key.toString());
List<Platform> list = selectList(new Platform());
for (Platform pp : list) {
redisCache.setCacheObject(getCacheKey(pp.getPlatformCode()), pp);
}
}
}
@Override
public Platform get(String platformCode) {
return redisCache.getCacheObject(getCacheKey(platformCode));
}
private String getCacheKey(String configKey) {
return CacheConstants.Platform + configKey;
}
}

View File

@ -0,0 +1,29 @@
package com.ff.sports.api.fb.address;
import com.dtflys.forest.callback.AddressSource;
import com.dtflys.forest.http.ForestAddress;
import com.dtflys.forest.http.ForestRequest;
import com.ff.base.system.service.ISysConfigService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author shi
* @date 2025/02/10
*/
@Component
public class FbAddress implements AddressSource {
public static final String API_BASE_URL = "fb.api.base.url";
@Resource
private ISysConfigService configService;
@Override
public ForestAddress getAddress(ForestRequest request) {
String apiBaseUrl = configService.selectConfigByKey(API_BASE_URL);
return new ForestAddress("https", apiBaseUrl, 443, "services");
}
}

View File

@ -0,0 +1,7 @@
package com.ff.sports.fb;
/**
* @author cengy
*/
public class A {
}

View File

@ -0,0 +1,110 @@
<?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.ff.game.mapper.PlatformMapper">
<resultMap type="Platform" id="PlatformResult">
<result property="id" column="id" />
<result property="sortNo" column="sort_no" />
<result property="platformCode" column="platform_code" />
<result property="platformName" column="platform_name" />
<result property="platformInfo" column="platform_info" typeHandler="com.ff.base.handler.JsonListHandler" javaType="com.ff.game.domain.PlatformInfo"/>
<result property="urlInfo" column="url_info" typeHandler="com.ff.base.handler.JsonHandler" javaType="com.ff.game.domain.UrlInfo"/>
<result property="keyInfo" column="key_info" typeHandler="com.ff.base.handler.JsonListHandler" javaType="com.ff.game.domain.KeyInfo"/>
<result property="langInfo" column="lang_info" typeHandler="com.ff.base.handler.JsonHandler" javaType="com.ff.game.domain.LangInfo"/>
<result property="currencyInfo" column="currency_info" typeHandler="com.ff.base.handler.JsonHandler" javaType="com.ff.game.domain.CurrencyInfo"/>
<result property="stopStatus" column="stop_status" />
<result property="createBy" column="create_by" />
<result property="createTime" column="create_time" />
<result property="updateBy" column="update_by" />
<result property="updateTime" column="update_time" />
</resultMap>
<sql id="selectVO">
select * from ff_platform
</sql>
<select id="selectList" parameterType="Platform" resultMap="PlatformResult">
<include refid="selectVO"/>
<where>
<if test="platformCode != null and platformCode != ''"> and platform_code = #{platformCode}</if>
<if test="platformName != null and platformName != ''"> and instr(platform_name,#{platformName}) &gt; 0</if>
<if test="stopStatus != null"> and stop_status = #{stopStatus}</if>
</where>
</select>
<select id="selectByPlatformCode" parameterType="String" resultMap="PlatformResult">
<include refid="selectVO"/>
where platform_code = #{platformCode}
</select>
<insert id="insertPlatform" parameterType="Platform">
insert into ff_platform
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if>
<if test="sortNo != null">sort_no,</if>
<if test="platformCode != null and platformCode != ''">platform_code,</if>
<if test="platformName != null and platformName != ''">platform_name,</if>
<if test="platformInfo != null and platformInfo != ''">platform_info,</if>
<if test="urlInfo != null and urlInfo != ''">url_info,</if>
<if test="keyInfo != null and keyInfo != ''">key_info,</if>
<if test="langInfo != null and langInfo != ''">lang_info,</if>
<if test="currencyInfo != null and currencyInfo != ''">currency_info,</if>
<if test="stopStatus != null">stop_status,</if>
<if test="createBy != null">create_by,</if>
<if test="createTime != null">create_time,</if>
<if test="updateBy != null">update_by,</if>
<if test="updateTime != null">update_time,</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if>
<if test="sortNo != null">#{sortNo}</if>
<if test="platformCode != null and platformCode != ''">#{platformCode},</if>
<if test="platformName != null and platformName != ''">#{platformName},</if>
<if test="platformInfo != null and platformInfo != ''">#{platformInfo},</if>
<if test="urlInfo != null and urlInfo != ''">#{urlInfo},</if>
<if test="keyInfo != null and keyInfo != ''">#{keyInfo},</if>
<if test="langInfo != null and langInfo != ''">#{langInfo},</if>
<if test="currencyInfo != null and currencyInfo != ''">#{currencyInfo},</if>
<if test="stopStatus != null">#{stopStatus},</if>
<if test="createBy != null">#{createBy},</if>
<if test="createTime != null">#{createTime},</if>
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
</insert>
<update id="updatePlatform" parameterType="Platform">
update ff_platform
<trim prefix="SET" suffixOverrides=",">
<if test="sortNo != null">sort_no = #{sortNo},</if>
<if test="platformCode != null and platformCode != ''">platform_code = #{platformCode},</if>
<if test="platformName != null and platformName != ''">platform_name = #{platformName},</if>
<if test="platformInfo != null and platformInfo != ''">platform_info = #{platformInfo},</if>
<if test="urlInfo != null and urlInfo != ''">url_info = #{urlInfo},</if>
<if test="keyInfo != null and keyInfo != ''">key_info = #{keyInfo},</if>
<if test="langInfo != null and langInfo != ''">lang_info = #{langInfo},</if>
<if test="currencyInfo != null and currencyInfo != ''">currency_info = #{currencyInfo},</if>
<if test="stopStatus != null">stop_status = #{stopStatus},</if>
<if test="createBy != null">create_by = #{createBy},</if>
<if test="createTime != null">create_time = #{updateTime},</if>
<if test="updateBy != null">update_by = #{updateBy},</if>
<if test="updateTime != null">update_time = #{updateTime},</if>
</trim>
where id = #{id}
</update>
<delete id="deleteById" parameterType="Long">
delete from ff_platform where id = #{id}
</delete>
<delete id="deleteByIds" parameterType="String">
delete from ff_platform where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
</mapper>