优化 RequestInfo 相关操作:

1. RequestInfoControllerV1 save 接口对 RequestInfo 参数做 @Valid 校验;
2. RequestInfoControllerV1 去除批量操作中的置匿名/去匿名,因为对于 RequestInfo
而言,当前已无字段标记匿名与否,仅凭是否配置用户名和密码来判断是否为匿名;
3. RequestInfoService 查找不到默认配置时创建 new RequestInfo(),虽数据表有触发器置 isDefault
= true,但此处仍手动 set,确保一致性;
4. RequestInfo 一些依赖 DeviceInfo 的字段,不做冗余,直接从 DeviceInfo <-
fingerprint/deviceName/softwareType 恢复。
This commit is contained in:
2026-06-09 16:23:33 +08:00
parent 287b124f7e
commit 2869994387
7 changed files with 51 additions and 45 deletions
@@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import jakarta.validation.Valid; import jakarta.validation.Valid;
import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
@@ -53,7 +52,7 @@ public class RequestInfoControllerV1 extends UpdateBoolServiceController<Request
@PostMapping("/save") @PostMapping("/save")
@ResponseBody @ResponseBody
public R<?> save(@RequestBody @NonNull RequestInfo requestInfo) { public R<?> save(@RequestBody @Valid @NonNull RequestInfo requestInfo) {
return super.save(requestInfo); return super.save(requestInfo);
} }
@@ -81,18 +80,11 @@ public class RequestInfoControllerV1 extends UpdateBoolServiceController<Request
return R.judge(getThisService().removeByIds(idArray)); return R.judge(getThisService().removeByIds(idArray));
} }
LambdaUpdateWrapper<RequestInfo> uw = new LambdaUpdateWrapper<>();
uw.in(RequestInfo::getId, idArray);
switch (op) {
default:
throw RException.badRequest("未知操作"); throw RException.badRequest("未知操作");
} }
}
private static enum RequestInfoBatchOp { private static enum RequestInfoBatchOp {
DELETE, DELETE
ENABLE_ANONYMOUS,
DISABLE_ANONYMOUS
} }
} }
@@ -4,7 +4,6 @@ import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model; import com.baomidou.mybatisplus.extension.activerecord.Model;
@@ -12,10 +11,8 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.AccessLevel;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.experimental.Accessors; import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.entity.config.AndroidSdkLevelConfig; import quant.rich.emoney.entity.config.AndroidSdkLevelConfig;
@@ -28,15 +25,21 @@ import quant.rich.emoney.util.TextUtils;
import quant.rich.emoney.validator.RequestInfoValid; import quant.rich.emoney.validator.RequestInfoValid;
/** /**
* 用于配置请求时的请求行为,一般而言,请求头与安卓系统的信息有关(build.prop) * <b>请求信息</b>
* 虽然部分请求对应服务器可能不进行审核,但合理的请求头能尽可能模仿真机行为,避免风险 * <p>
* @see DeviceInfoConfig * 用于配置请求时的参数,包括请求头等。若使用该请求头登录成功,则将会存储鉴权信息。
* @see AndroidSdkLevelConfig *
* @see ChromeVersionsConfig * 一般而言,请求头与系统的信息有关(build.prop)
* 虽然服务器可能不进行请求头审核,但合理的请求头能尽可能模仿真机行为,避免风险。
* <p> * <p>
* SQLite 表 request_info 使用触发器维护默认请求配置的一致性:新增或更新 is_default = 1 * SQLite 表 request_info 使用触发器维护默认请求配置的一致性:新增或更新 is_default = 1
* 时会把其他记录置为非默认;不允许把最后一条默认请求配置改为非默认,也不允许删除默认请求配置。 * 时会把其他记录置为非默认;不允许把最后一条默认请求配置改为非默认,也不允许删除默认请求配置。
* 这部分约束不在 Java 代码里重复实现,调整表结构或导入数据时需要同步检查触发器。 * 这部分约束不在 Java 代码里重复实现,调整表结构或导入数据时需要同步检查触发器。
*
* @see DeviceInfoConfig
* @see AndroidSdkLevelConfig
* @see ChromeVersionsConfig
* @See RequestInfoValidator
*/ */
@Data @Data
@EqualsAndHashCode(callSuper=false) @EqualsAndHashCode(callSuper=false)
@@ -113,9 +116,10 @@ public class RequestInfo extends Model<RequestInfo> {
* @see DeviceInfoConfig * @see DeviceInfoConfig
* @see DeviceInfo * @see DeviceInfo
*/ */
@Setter(AccessLevel.PRIVATE) public String getAndroidVersion() {
@TableField(exist=false) DeviceInfo deviceInfo = getDeviceInfo();
private String androidVersion; return deviceInfo == null ? null : deviceInfo.getVersionRelease();
}
/** /**
* <b>用于:</b><ul> * <b>用于:</b><ul>
@@ -127,9 +131,13 @@ public class RequestInfo extends Model<RequestInfo> {
* @see DeviceInfo * @see DeviceInfo
* @see AndroidSdkLevelConfig * @see AndroidSdkLevelConfig
*/ */
@Setter(AccessLevel.PRIVATE) public String getAndroidSdkLevel() {
@TableField(exist=false) String androidVersion = getAndroidVersion();
private String androidSdkLevel; if (StringUtils.isBlank(androidVersion)) {
return null;
}
return String.valueOf(androidSdkLevelConfig.getSdkLevel(androidVersion));
}
/** /**
* <b>用于:</b><ul> * <b>用于:</b><ul>
@@ -183,8 +191,10 @@ public class RequestInfo extends Model<RequestInfo> {
* @see DeviceInfoConfig * @see DeviceInfoConfig
* *
*/ */
@TableField(exist=false) public String getBuildId() {
private String buildId; DeviceInfo deviceInfo = getDeviceInfo();
return deviceInfo == null ? null : deviceInfo.getBuildId();
}
/** /**
* <b>用于:</b><ul> * <b>用于:</b><ul>
@@ -218,21 +228,29 @@ public class RequestInfo extends Model<RequestInfo> {
/** /**
* 从 deviceInfo 设置相关字段 * 从 deviceInfo 设置相关字段
* @param deviceInfo * @param deviceInfo
* @return * @return 更新过的 RequestInfo 本身
*/ */
public RequestInfo setRelativeFieldsFromDeviceInfo(DeviceInfo deviceInfo) { public RequestInfo setRelativeFieldsFromDeviceInfo(DeviceInfo deviceInfo) {
if (deviceInfo == null) { if (deviceInfo == null) {
throw new NullPointerException("deviceInfo is null"); throw new NullPointerException("deviceInfo is null");
} }
deviceName = deviceInfo.getModel(); deviceName = deviceInfo.getModel();
androidVersion = deviceInfo.getVersionRelease();
androidSdkLevel = String.valueOf(androidSdkLevelConfig.getSdkLevel(androidVersion));
softwareType = deviceInfo.getDeviceType(); softwareType = deviceInfo.getDeviceType();
fingerprint = deviceInfo.getFingerprint(); fingerprint = deviceInfo.getFingerprint();
buildId = deviceInfo.getBuildId();
return this; return this;
} }
/**
* @return 获取由相应字段指定的 DeviceInfo
*/
@JsonIgnore
private DeviceInfo getDeviceInfo() {
if (ObjectUtils.anyNull(deviceName, fingerprint, softwareType)) {
return null;
}
return DeviceInfo.from(deviceName, fingerprint, softwareType);
}
/** /**
* 设置密码:<ul> * 设置密码:<ul>
* <li>null or empty,保存空字符串</li> * <li>null or empty,保存空字符串</li>
@@ -264,13 +282,7 @@ public class RequestInfo extends Model<RequestInfo> {
* @see RequestInfo#setRelativeFieldsFromDeviceInfo * @see RequestInfo#setRelativeFieldsFromDeviceInfo
*/ */
public RequestInfo setFingerprint(String fingerprint) { public RequestInfo setFingerprint(String fingerprint) {
if (ObjectUtils.allNotNull(deviceName, softwareType, fingerprint, androidSdkLevelConfig)) {
DeviceInfo deviceInfo = DeviceInfo.from(deviceName, fingerprint, softwareType);
setRelativeFieldsFromDeviceInfo(deviceInfo);
}
else {
this.fingerprint = fingerprint; this.fingerprint = fingerprint;
}
return this; return this;
} }
@@ -44,6 +44,7 @@ public class RequestInfoService extends SqliteServiceImpl<RequestInfoMapper, Req
); );
if (requestInfo == null) { if (requestInfo == null) {
requestInfo = new RequestInfo(); requestInfo = new RequestInfo();
requestInfo.setIsDefault(true);
save(requestInfo); save(requestInfo);
} }
return requestInfo; return requestInfo;
@@ -14,7 +14,7 @@ import jakarta.validation.Payload;
@Target({ ElementType.TYPE }) @Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
public @interface RequestInfoValid { public @interface RequestInfoValid {
String message() default "非法的 EmoneyRequestConfig"; String message() default "非法的 RequestInfo";
Class<?>[] groups() default {}; Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {}; Class<? extends Payload>[] payload() default {};
} }
@@ -10,6 +10,9 @@ import quant.rich.emoney.entity.config.DeviceInfoConfig;
import quant.rich.emoney.entity.sqlite.RequestInfo; import quant.rich.emoney.entity.sqlite.RequestInfo;
import quant.rich.emoney.interfaces.IValidator; import quant.rich.emoney.interfaces.IValidator;
/**
* RequestInfo 校验器
*/
public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> { public class RequestInfoValidator implements IValidator, ConstraintValidator<RequestInfoValid, RequestInfo> {
static final Pattern androidIdPattern = Pattern.compile("^[0-9a-f]{16}$"); static final Pattern androidIdPattern = Pattern.compile("^[0-9a-f]{16}$");
@@ -158,7 +158,7 @@
} }
else { else {
$(non).children('label').children('span').remove(); $(non).children('label').children('span').remove();
$(non).find('lay-verify').removeAttr('lay-verify'); $(non).find('[lay-verify]').removeAttr('lay-verify');
} }
}); });
}); });
@@ -58,9 +58,7 @@
Helper.renderDropdown({ Helper.renderDropdown({
elem: '.operdown', elem: '.operdown',
data: [ data: [
{title: '删除', op: 'DELETE'}, {title: '删除', op: 'DELETE'}],
{title: '开启匿名', op: 'ENABLE_ANONYMOUS'},
{title: '关闭匿名', op: 'DISABLE_ANONYMOUS'}],
tableFilter: 'requestInfos', tableFilter: 'requestInfos',
url: '/admin/v1/manage/requestInfo/batchOp', url: '/admin/v1/manage/requestInfo/batchOp',
idName: 'id' idName: 'id'