删除 EmoneyRequestConfig 和 ProxyConfig 设置,改为数据库(SQLite)配置。默认配置的设置和删除逻辑由

SQLite 触发器配置。
This commit is contained in:
2025-11-15 14:57:02 +08:00
parent 6ccfe67aff
commit edcbfd4ffd
77 changed files with 1240 additions and 1620 deletions

View File

@@ -3,12 +3,9 @@ package quant.rich.emoney.controller.common;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import quant.rich.emoney.pojo.dto.R;
import quant.rich.emoney.service.AuthService;
@Controller

View File

@@ -0,0 +1,122 @@
package quant.rich.emoney.controller.common;
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.LayPageReq;
import quant.rich.emoney.pojo.dto.LayPageResp;
import quant.rich.emoney.pojo.dto.R;
/**
* 在控制器中提供实体类的 service<p>
*
* 继承后,可直接通过 {@code thisType} 和 {@code thisService} 获取实体类型和对应的服务实例<p>
* 也获得部分能力,但控制方法及 Mapping 路径要继承后自己写。<p>
* 可获得的能力:
* <ul>
* <li>list
* <li>getOne
* <li>delete
* <ul>
*
* @param <T> 实体类型
*/
@Slf4j
public abstract class ServiceController<T> extends BaseController {
@Autowired
private ApplicationContext ctx;
protected IService<?> thisService;
protected Class<?> thisType;
@PostConstruct
void init() {
@SuppressWarnings("rawtypes")
Map<String, IService> beans = ctx.getBeansOfType(IService.class);
ResolvableType thisType = ResolvableType.forClass(this.getClass()).as(ServiceController.class);
@SuppressWarnings("unchecked")
// 获取本类的实体类
Class<T> clazz = (Class<T>) thisType.getGeneric(0).resolve();
this.thisType = clazz;
for (IService<?> service : beans.values()) {
ResolvableType type = ResolvableType.forClass(service.getClass()).as(IService.class);
Class<?> entityType = type.getGeneric(0).resolve();
if (entityType == clazz) {
this.thisService = service;
}
}
if (thisService == null) {
log.error("获取本例实体类服务失败,请检查");
}
}
@SuppressWarnings("unchecked")
protected IService<T> getThisService() {
return (IService<T>)this.thisService;
}
/**
* 返回实例类列表
* @param pageReq
* @return
*/
protected LayPageResp<?> list(LayPageReq<T> pageReq) {
Page<T> planPage = getThisService().page(pageReq);
return new LayPageResp<>(planPage);
}
/**
* 根据 id 获取实例化对象。如果 id 为空则返回通过默认无参构造器构造的新实例化对象
* @param id
* @return
*/
protected R<?> getOne(Serializable id) {
// id 为空,返回一个新实例化对象
if (id == null) {
try {
return R.ok(thisType.getConstructor().newInstance());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
final String s = "根据默认构造器创建新实例化对象失败";
log.error(s, e);
throw RException.internalServerError(s);
}
}
// 否则从数据库取
T exist = getThisService().getById(id);
return R.judge(exist != null, exist, "无法找到对应 ID 的 ProxySetting");
}
/**
* 保存
* @param object
* @return
*/
protected R<?> save(T object) {
return
R.judge(
() -> getThisService().saveOrUpdate(object),
"新增或保存失败");
}
/**
* 删除
* @param id
* @return
*/
protected R<?> delete(Serializable id) {
return R.judge(getThisService().removeById(id), "删除失败,是否已删除?");
}
}

View File

@@ -1,91 +0,0 @@
package quant.rich.emoney.controller.common;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.R;
@Slf4j
public abstract class UpdateBoolController<T> extends BaseController {
ObjectMapper mapper = new ObjectMapper();
@Autowired
private ApplicationContext ctx;
private Map<Class<?>, IService<?>> serviceMap;
@PostConstruct
void init() {
serviceMap = new HashMap<>();
@SuppressWarnings("rawtypes")
Map<String, IService> beans = ctx.getBeansOfType(IService.class);
for (IService<?> service : beans.values()) {
ResolvableType type = ResolvableType.forClass(service.getClass()).as(IService.class);
Class<?> entityType = type.getGeneric(0).resolve();
if (entityType != null) {
serviceMap.put(entityType, service);
}
}
}
@SuppressWarnings("unchecked")
public IService<T> getService(Class<T> entityClass) {
return (IService<T>) serviceMap.get(entityClass);
}
@PostMapping("/updateBool")
@ResponseBody
protected
R<?> updateBool(String id, String field, Boolean value) {
ResolvableType type = ResolvableType.forClass(this.getClass()).as(UpdateBoolController.class);
@SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) type.getGeneric(0).resolve();
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
Object converted = mapper.convertValue(id, tableInfo.getKeyType());
// 获取 Service
IService<T> s = getService((Class<T>) clazz);
try {
String idField = tableInfo.getKeyColumn();
Field declaredField = clazz.getDeclaredField(field);
Optional<TableFieldInfo> fieldInfo = tableInfo.getFieldList().stream()
.filter(f -> f.getProperty().equals(field))
.findFirst();
if (declaredField.getType().equals(Boolean.class)) {
return R.judge(s.update(
new UpdateWrapper<T>()
.set(fieldInfo.get().getColumn(), value)
.eq(idField, converted)
), "更新失败,请查看日志");
}
}
catch (Exception e) {
log.error("update bool failed", e);
}
throw RException.badRequest().setLogRequest(true);
}
}

View File

@@ -0,0 +1,86 @@
package quant.rich.emoney.controller.common;
import java.lang.reflect.Field;
import java.util.Optional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import quant.rich.emoney.exception.RException;
import quant.rich.emoney.pojo.dto.R;
/**
* 更新实体类中 Boolean 字段的抽象控制器,一般用于实体类中包含 Boolean 字段的前端更新
* <p>
* 前端实体类数据列表中,常有 CheckBox 或 Switch 等控件,希望通过点击数据表中的控件直接修改行对象
* Boolean 值的,可用该方法。需要引入功能的需 extends 本类,如对 {@code Plan} 生效,则可在其控制器
* {@code PlanController} 中:<p>
*
* <code> PlanController <b>extends</b> UpdateBoolController&lt;Plan></code>
* @param <T> 实体类型
* @see #updateBool(String, String, Boolean)
*/
@Slf4j
public abstract class UpdateBoolServiceController<T> extends ServiceController<T> {
protected ObjectMapper mapper = new ObjectMapper();
/**
* 更新布尔值主方法,以 form 形式 POSTuri: /updateBool表单字段名需与该方法参数名一致
* @param id 欲修改的实体类的实例化对象的主键值
* @param field 欲修改的实体类的实例化对象的布尔字段名
* @param value 需要修改为的布尔值
* @return
*/
@PostMapping("/updateBool")
@ResponseBody
protected
R<?> updateBool(String id, String field, Boolean value) {
// 获取表信息
TableInfo tableInfo = TableInfoHelper.getTableInfo(thisType);
Object converted = mapper.convertValue(id, tableInfo.getKeyType());
// 获取 Service
try {
// 获取主键名
String idField = tableInfo.getKeyColumn();
// 获取指定布尔字段的字段信息
Field declaredField = thisType.getDeclaredField(field);
// 获取指定布尔字段在数据表中的映射字段信息
Optional<TableFieldInfo> fieldInfo = tableInfo.getFieldList().stream()
.filter(f -> f.getProperty().equals(field))
.findFirst();
if (fieldInfo.isEmpty()) {
throw RException.badRequest("无法根据 field: " + field + " 找到类内字段信息");
}
if (declaredField.getType().equals(Boolean.class)
|| declaredField.getType().equals(boolean.class)
) {
return R.judge(getThisService().update(
new UpdateWrapper<T>()
.set(fieldInfo.get().getColumn(), value)
.eq(idField, converted)
), "更新失败,请查看日志");
}
else {
throw RException.badRequest("field: " + field + " 不为布尔值类型字段");
}
}
catch (NoSuchFieldException | SecurityException e) {
throw RException.badRequest("获取字段 " + field + " 错误");
}
}
}