前言:近期因为项目需求变更频繁,大多是一些列表字段的变更。为此封装了一个自定义分页查询,主要用到java的反射、自定义注解等。
1. 人员信息分页查询
controller 层
java
@ApiOperation(value="人员信息-分页查询")
@PostMapping("page")
public Result<Page<UserVO>> getUserPage(@RequestBody PageParamDTO queryParams){
return new SuccessResult<>(userService.getUserPage(queryParams));
}
serviceImpl
java
@Override
public Page<UserVO> getUserPage(PageParamDTO queryParams){
Page<UserVO> pageResult = new Page<>(queryParams.getPageNo(),queryParams.getPageSize());
// 封装查询条件
UserQueryDTO params = this.getQueryCondition(queryParams.getParams());
return this.baseMapper.getPage(pageResult,params);
}
以上为用户列表的一个普通分页查询。再不修改原代码的情况进行改造。
2. 代码改造
2.1. 增加自定列配置表
sql
CERATE TABLE "CUSTOM_CONFIG_COLUMN"
(
"ID" VARCHAR2(32) NOT NULL,
"CREATE_TIME" TIMESTAMP(6),
"CREATE_USER_ID" VARCHAR2(32),
"UPDATE_TIME" TIMESTAMP(6),
"UPDATE_USER_ID" VARCHAR2(32),
"ENABLE" CHAR(1) DEFAULT 'Y',
"REMOVE" CHAR(1) DEFAULT 'N',
"VIEW_NAME" VARCHAR2(100),
"COLUMN_NAME" VARCHAR2(100),
"ALIGN" VARCHAR2(100),
"COLUMN_FIELD" VARCHAR2(100),
"HEADER" TINYINT(1),
"QUERY" TINYINT(1),
"ROW_KEY" TINYINT(1),
"SHOW" TINYINT(1),
"SORT_NO" NUMBER(2),
"TRANSLATION" VARCHAR2(100),
"IS_FILE_DOWNLOAD" TINYINT(1)
);
COMMENT ON TABLE "CUSTOM_CONFIG_COLUMN" IS "自定义列";
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."ID" IS '主键ID';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."ENABLE" IS '启用状态';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."REMOVE" IS '逻辑删除';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."VIEW_NAME" IS '视图名称(自定义列标识)';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."COLUMN_NAME" IS '列名';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."ALIGN" IS '列内容对齐方式';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."COLUMN_FIELD" IS '列字段';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."HEADER" IS '是否为表头';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."QUERY" IS '是否作为查询条件';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."ROW_KEY" IS '是否为rowKey,即主键';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."SHOW" IS '是否显示';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."SORT_NO" IS '排序';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."TRANSLATION" IS '转译';
COMMENT ON COLUMN "CUSTOM_CONFIG_COLUMN"."IS_FILE_DOWNLOAD" IS '是否为文件下载';
示例数据
sql
-- ID 隐藏主键
INSERT INTO "CUSTOM_CONFIG_COLUMN" ("ID","CREATE_TIME","CREATE_TIME","CREATE_USER_ID","UPDATE_TIME","UPDATE_USER_ID","ENABLE","REMOVE","VIEW_NAME","COLUMN_NAME","ALIGN","COLUMN_FIELD","HEADER","QUERY","ROW_KEY","SHOW","SORT_NO","TRANSLATION","IS_FILE_DOWNLOAD")
VALUES ('001','2026-12-03 15:55:20','00012',null,null,'Y','N','USER_PAGE_VIEW','ID','center','id','0','0','1','0',1,null,'0');
-- USER_ID 人员Id
INSERT INTO "CUSTOM_CONFIG_COLUMN" ("ID","CREATE_TIME","CREATE_TIME","CREATE_USER_ID","UPDATE_TIME","UPDATE_USER_ID","ENABLE","REMOVE","VIEW_NAME","COLUMN_NAME","ALIGN","COLUMN_FIELD","HEADER","QUERY","ROW_KEY","SHOW","SORT_NO","TRANSLATION","IS_FILE_DOWNLOAD")
VALUES ('002','2026-12-03 15:55:20','00012',null,null,'Y','N','USER_PAGE_VIEW','用户姓名','center','userId','1','1','0','1',2,'USER_KEY','0');
-- ORG_ID 组织id
INSERT INTO "CUSTOM_CONFIG_COLUMN" ("ID","CREATE_TIME","CREATE_TIME","CREATE_USER_ID","UPDATE_TIME","UPDATE_USER_ID","ENABLE","REMOVE","VIEW_NAME","COLUMN_NAME","ALIGN","COLUMN_FIELD","HEADER","QUERY","ROW_KEY","SHOW","SORT_NO","TRANSLATION","IS_FILE_DOWNLOAD")
VALUES ('003','2026-12-03 15:55:20','00012',null,null,'Y','N','USER_PAGE_VIEW','用户组织','center','orgId','1','1','0','1',3,null,'0');
-- 身份类型 数据字典
INSERT INTO "CUSTOM_CONFIG_COLUMN" ("ID","CREATE_TIME","CREATE_TIME","CREATE_USER_ID","UPDATE_TIME","UPDATE_USER_ID","ENABLE","REMOVE","VIEW_NAME","COLUMN_NAME","ALIGN","COLUMN_FIELD","HEADER","QUERY","ROW_KEY","SHOW","SORT_NO","TRANSLATION","IS_FILE_DOWNLOAD")
VALUES ('004','2026-12-03 15:55:20','00012',null,null,'Y','N','USER_PAGE_VIEW','身份类型','center','identityType','1','1','0','1',3,'IDENTITY_TYPE','0');
-- 地址 普通字段
INSERT INTO "CUSTOM_CONFIG_COLUMN" ("ID","CREATE_TIME","CREATE_TIME","CREATE_USER_ID","UPDATE_TIME","UPDATE_USER_ID","ENABLE","REMOVE","VIEW_NAME","COLUMN_NAME","ALIGN","COLUMN_FIELD","HEADER","QUERY","ROW_KEY","SHOW","SORT_NO","TRANSLATION","IS_FILE_DOWNLOAD")
VALUES ('005','2026-12-03 15:55:20','00012',null,null,'Y','N','USER_PAGE_VIEW','地址','center','address','1','1','0','1',3,null,'0');
2.2. 编写自定义注解
java
import java.lang.annotaion.*
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoTranslation {
/**
* 自定义视图名称
*/
String viewName() default "";
}
2.3. 编写自动转译切面
java
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ideal.common.annotation.AutoTranslation;
import com.ideal.common.bean.vo.ConfigColumnVO;
import com.ideal.common.bean.vo.PageColumnVO;
import com.ideal.common.service.ICommonService;
import com.ideal.common.util.SpringUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectkj.lang.ProceedingJoinPoint;
import org.aspectkj.lang.annotation.Around;
import org.aspectkj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import java.unit.List;
@Slf4j
@Aspect
@Component
public class AutoTranslationAspect {
@SneakyThrows
@Around(value = "@annotation(autoTranslation)")
public <T> Object around(ProceedingJoinPoint joinPoint, AutoTranslation autoTranslation){
log.debug("》》》》》》》》 AutoTranslationAspect start execution.");
Object proceed = joinPoint.proceed();
PageColumnVO<T> result = null;
if(proceed instanceof Page){
result = new PageColumnVO<>((Page<T>) proceed);
ICommonService commonService = SpringUtils.getBean(ICommonService.class);
List<ConfigColumnVO> columnVOList = commonService.translationList(result.getRecords(), autoTranslation.viewName());
result.fillConfigList(columnVOList);
}
return result == null ? proceed : result;
}
}
其他相关依赖类
- 包含自定义列的分页对象
java
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.Getter;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.List;
@Getter
public class PageColumnVO<T> extends Page<T> {
private List<ConfigColumnVO> configList = new ArrayList<>();
public PageColumnVO<T> fillConfigList(List<ConfigColumnVO> configList ){
if(CollectionUtils.isEmpty(configList)){
return this;
}
this.configList = configList;
return this;
}
public PageColumnVO(Page<T> page){
BeanUtils.copyProperties(page, this);
}
}
- 自定义列VO
java
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ConfigColumnVO {
@ApiModelProperty(value = "主键ID")
private String id;
@ApiModelProperty(value = "视图名称")
private String viewName;
@ApiModelProperty(value = "列名")
private String columnName;
@ApiModelProperty(value = "列内容对齐方式")
private String align;
@ApiModelProperty(value = "列字段")
private String columnField;
@ApiModelProperty(value = "是否为表头")
private boolean header;
@ApiModelProperty(value = "是否作为查询条件")
private boolean query;
@ApiModelProperty(value = "是否为rowKey")
private boolean rowKey;
@ApiModelProperty(value = "是否显示")
private boolean show;
@ApiModelProperty(value = "排序")
private Integer sortNo;
@ApiModelProperty(value = "转译key")
private String translation;
}
- Spirng工具类
java
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
/**
* spirng工具类 方便在非spring管理环境中获取bean
**/
@Component("springUtils")
public final class SpringUtils implements BeanFactoryPostProcessor {
// Spring应用上下文环境
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
SpringUtils.beanFactory = beanFactory;
}
/**
* 获取类型为requiredType的对象
**/
public static <T> T getBean(Class<T> clazz) {
return beanFactory.getBean(clazz);
}
public static Object getBean(String beanName) {
return beanFactory.getBean(beanName);
}
public static <T> Map<String, T> getBeansOfType(Class<T> clazz) {
return beanFactory.getBeansOfType(clazz);
}
}
- 业务操作类(此处仅提供实现类示例)
java
public class CommonServiceImpl implements ICommonService {
// 转译方法
@Override
public <T> List<ConfigColumnVO> translationList(List<T> records, String viewName) {
// 获取自定义列
List<ConfigColumnVO> columnVOList = configColumnService.getConfigColumns(viewName);
if(CollectionUtils.isEmpty(records)) {
return columnVOList;
}
Map<String,ConfigColumnVO> columnVOMap = columnVOList.stream().filter(item -> StrUtil.isNotBlank(item.getTranslation())).collect(Collectors.toMap(ConfigColumnVO::getColumnField, a -> a, (k1, k2) -> k1));
if(CollectionUtils.isNotEmpty(columnVOMap)) {
// 组织ID,名称Map
Map<String, String> orgMap = getOrgMap();
// 人员ID,名称Map
Map<String, String> userMap = getUserMap();
for(Map.Entry<String, ConfigColumnVO> entry : columnVOMap.entrySet()){
for(T t : records){
try{
Field field = t.getClass().getDeclaredField(entry.getKey());
field.setAccessible(true);
String translation = entry.getValue().getTranslation();
if("USER_KEY".equals(translation)){
// 人员转译
field.set(t,userMap.get(field.get(t).toString()));
}else if("ORG_KEY".equals(translation)){
// 组织转译
field.set(t,orgMap.get(field.get(t).toString()));
}else{
// 数据字典
Map<String, String> dictMap = dictCacheUtil.getDictMapByTypeCode(translation);
field.set(t,dictMap.get(field.get(t).toString()));
}
} catch (Exception e){
log.warn("CommonServiceImpl.translationList error. msg:{}", e.getMessage());
}
}
}
}
}
return columnVOList;
}
3. 使用示例
- 在数据库配置好对应的自定义列
- 在原来的方法上使用自定义注解指定自定义列,即可完成改造。
java
@Override
@AutoTranslation(viewName = "USER_PAGE_VIEW")
public Page<UserVO> getUserPage(PageParamDTO queryParams){
Page<UserVO> pageResult = new Page<>(queryParams.getPageNo(),queryParams.getPageSize());
// 封装查询条件
UserQueryDTO params = this.getQueryCondition(queryParams.getParams());
return this.baseMapper.getPage(pageResult,params);
}