java反射、自定义注解的应用(自定义分页)

前言:近期因为项目需求变更频繁,大多是一些列表字段的变更。为此封装了一个自定义分页查询,主要用到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;
	}
}

其他相关依赖类

  1. 包含自定义列的分页对象
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);
	}
	
}
  1. 自定义列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;	

}
  1. 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);
	}
}
  1. 业务操作类(此处仅提供实现类示例)
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. 使用示例

  1. 在数据库配置好对应的自定义列
  2. 在原来的方法上使用自定义注解指定自定义列,即可完成改造。
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);
}
相关推荐
BLUcoding2 小时前
接口服务公网超时排查记录:SecureRandom 阻塞问题分析与解决
java·linux·springboot·aes·securerandom
yuniko-n2 小时前
【JUC】Lock 和 synchronzied 锁
java
西柚小萌新2 小时前
【LLM&&AI应用开发 八股文】--4.3.Agent智能体(下)
java·开发语言·数据库
北极有牛2 小时前
cpp学习笔记--常量指针
java·开发语言·算法
java资料站2 小时前
二、Spring AI Alibaba · ChatModel
java·windows·spring
十年Java程序媛2 小时前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
caoerzhong2 小时前
JeeWMS 开源 WMS 部署避坑指南:Java 仓库管理系统的环境基线、四类根因与可复现交付
java·开发语言·开源
用户3721574261352 小时前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java
for_ever_love__3 小时前
MySQL 全文索引实战:FULLTEXT、ngram 中文分词与 MATCH AGAINST 到底该怎么用
java·python·mysql·全文检索·分词·索引·ngram