zoukankan      html  css  js  c++  java
  • spring boot 利用切面和反射进行自动关联查询

    1.定义注解类:

    QueryAuto:

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * ClassName: Query <br/>
     * Function: 模块关联查询注解<br/>
        用于返回list等方法上
     */
    @Documented
    @Inherited
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface QueryAuto {
    	
    }
    

     QueryField:

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * ClassName: QueryField <br/>
     * Function: 模块关联查询注解<br/>
     * <p>比如字典数据,我们表里面都存的字典id,之前的开发模式是在业务模块的sql里各种left join去查询字典名称.</p> 
     * <p>现在的做法是在实体对象的字典id属性上加上此注解,并写上字典名称属性,会自动去查询数据库,赋值于字典名称属性上去.</p> 
    
     */
    @Documented
    @Inherited
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface QueryField {
    	
    	/**
    	 * module:(业务模块编码,默认为Dic 字典模块,其他模块的话需要遵循一定的命名规则,
    	 * 			详见com.talkweb.query.common.QueryConstant 模块定义常量). <br/>
    	 * @author gavin
    	 * @return
    	 */
    	public String module() default "Dic";
    	
    	/**
    	 * nameField:(字典数据名称属性字段). <br/>
    	 * @author gavin
    	 * @return
    	 */
    	public String nameField();
    }
    

    2.定义自动查询的属性实体类

    import java.io.Serializable;
    
    /**
     * ClassName:QueryFieldEntity <br/>
     * Function: 需要自动查询的字段属性对象. <br/>
     */
    public class QueryFieldEntity implements Serializable {
    	private static final long serialVersionUID = 1L;
    	
    	private String idFieldName;		//id属性的字段名称
    	private String nameFieldName;	//name属性字段名称
    	private String module;			//需要查询的模块名称
    	
    	public String getIdFieldName() {
    		return idFieldName;
    	}
    	public void setIdFieldName(String idFieldName) {
    		this.idFieldName = idFieldName;
    	}
    	public String getNameFieldName() {
    		return nameFieldName;
    	}
    	public void setNameFieldName(String nameFieldName) {
    		this.nameFieldName = nameFieldName;
    	}
    	public String getModule() {
    		return module;
    	}
    	public void setModule(String module) {
    		this.module = module;
    	}
    }
    

    3.定义查询工具类:用于获取需要查询的字段

    import java.lang.reflect.Field;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    import com.annotation.QueryField;
    import com.query.entity.QueryFieldEntity;
    
    /**
     * ClassName:QueryUtil <br/>
     * Function: 自动查询工具类. <br/>
     */
    public class QueryUtil {
    	
    	/**
    	 * getQueryAutoField:(得到对象中需要自动查询的字段). <br/>
    	 * @author gavin
    	 * @param object
    	 * @return
    	 */
    	public static List<QueryFieldEntity> getQueryAutoField(Object object){
    		List<QueryFieldEntity> list = new ArrayList<QueryFieldEntity>();
    		Class<?> cls = object.getClass();
    	    Field[] fields = cls.getDeclaredFields();  
    		List<Field> fieldList = new ArrayList<Field>(Arrays.asList(fields));
    	    //获取父类字段
    	    Class<?> supercls = cls.getSuperclass();
    	    Field[] superfields = supercls.getDeclaredFields();  
    	   
    	    fieldList.addAll( new ArrayList<Field>(Arrays.asList(superfields)));
    	    for (Field field : fieldList) {
    	    	field.setAccessible(true);
    	    	QueryField queryField = field.getAnnotation(QueryField.class);
    	    	if(queryField != null){
    	    		QueryFieldEntity entity = new QueryFieldEntity();
    	    		entity.setIdFieldName(field.getName());
    	    		entity.setNameFieldName(queryField.nameField());
    	    		entity.setModule(queryField.module());
    	    		list.add(entity);
    	    	}
    	    }
    		return list;
    	}
    	
    	/**
    	 * getQueryAutoField:(得到对象中需要自动查询的字段). <br/>
    	 * @author gavin
    	 * @param object
    	 * @return
    	 */
    	public static List<QueryFieldEntity> getSuperQueryAutoField(Object object){
    		List<QueryFieldEntity> list = new ArrayList<QueryFieldEntity>();
    		Class<?> supercls = object.getClass().getSuperclass();
    	    Field[] fields = supercls.getDeclaredFields();  
    	    for (Field field : fields) {
    	    	field.setAccessible(true);
    	    	QueryField queryField = field.getAnnotation(QueryField.class);
    	    	if(queryField != null){
    	    		QueryFieldEntity entity = new QueryFieldEntity();
    	    		entity.setIdFieldName(field.getName());
    	    		entity.setNameFieldName(queryField.nameField());
    	    		entity.setModule(queryField.module());
    	    		list.add(entity);
    	    	}
    	    }
    		return list;
    	}
    }
    

    4.定义查询接口:用于处理不同类型的数据

    /**
     * ClassName:Query <br/>
     * Function: TODO ADD FUNCTION. <br/>
     * Date:     2017年6月27日 上午9:47:04 <br/>
    
     */
    public interface Query {
    	/**
    	 * doPage:(处理分页数据). <br/>
    	 * @author gavin
    	 * @param object
    	 */
    	public void doPage(Object object);
    	
    	/**
    	 * doList:(处理简单列表数据). <br/>
    	 * @author gavin
    	 * @param object
    	 */
    	public void doList(Object object);
    	
    	/**
    	 * doObject:(处理简单实体对象数据). <br/>
    	 * @author gavin
    	 * @param object
    	 */
    	public void doObject(Object object);
    }
    

     

    package com.query.query.impl;
    
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.List;
    
    import javax.annotation.Resource;
    
    import org.springframework.stereotype.Component;
    
    import com.common.Page;
    import com.query.adapter.QueryAdapter;
    import com.query.common.QueryUtil;
    import com.query.entity.QueryFieldEntity;
    import com.query.query.Query;
    
    /**
     * ClassName:QueryImpl <br/>
     * Function: 自动查询实现类. <br/>
     * Date:     2017年6月27日 上午9:54:02 <br/>
     * @author   gavin
     * @since    JDK 1.6
     */
    @Component
    public class QueryImpl implements Query {
    	@Resource(name="queryAdapter")
    	private QueryAdapter queryAdapter;
    	
    	@Override
    	public void doPage(Object object) {
    		Page page = (Page)object;
    		try {
    			Method m = page.getClass().getMethod("getContent");
    			List list = (List)m.invoke(page);
    	    	if(list != null && list.size() > 0){
    	    		Object o = list.get(0);
    				List<QueryFieldEntity> fieldList = QueryUtil.getQueryAutoField(o);
    				if(fieldList != null && fieldList.size() > 0){
    					for(Object ob : list){
    						for(QueryFieldEntity field : fieldList){
    							queryAdapter.handle(ob, field);
    						}
    					}
    				}
    	    	}
    		} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    			e.printStackTrace();
    		}
    	}
    
    	@Override
    	public void doList(Object object) {
    		List list = (List)object;
    		if(list != null && list.size() > 0){
    			Object o = list.get(0);
    			List<QueryFieldEntity> fieldList = QueryUtil.getQueryAutoField(o);
    			if(fieldList != null && fieldList.size() > 0){
    				for(Object ob : list){
    					for(QueryFieldEntity field : fieldList){
    						queryAdapter.handle(ob, field);
    					}
    				}
    			}
    		}
    	}
    
    	@Override
    	public void doObject(Object object) {
    		List<QueryFieldEntity> fieldList = QueryUtil.getQueryAutoField(object);
    		if(fieldList != null && fieldList.size() > 0){
    			for(QueryFieldEntity field : fieldList){
    				queryAdapter.handle(object, field);
    			}
    		}
    	}
    }
    

      

    5.定义查询适配器:用于使用不同的模块(关联表)

    package com.talkweb.query.adapter;
    
    import java.lang.reflect.Field;
    
    import com.config.ApplicationContextRegister;
    import org.springframework.stereotype.Component;
    import org.springframework.web.context.ContextLoader;
    
    import com.query.entity.QueryFieldEntity;
    import com.query.query.QueryModule;
    
    /**
     * ClassName:QueryAdapter <br/>
     * Function: 自动查询适配器. <br/>
     */
    @Component("queryAdapter")
    public class QueryAdapter {
    	
    	/**
    	 * handle:(根据不同模块,适配不同的接口实现类处理查询). <br/>
    	 * @author gavin
    	 * @param object
    	 * @param field
    	 */
    	public void handle(Object object,QueryFieldEntity field) {
    		if(field.getModule() != null && !"".equals(field.getModule())){
    			//这里必须注意,关于字段上的配置的Module属性,必须要和QueryModule接口实现类的后缀一致,
    			//这里getBean的bean的名称就是queryModuleOf + Module属性!!!!
    			QueryModule queryModule = (QueryModule) ApplicationContextRegister.getApplicationContext()
    													.getBean("queryModuleOf"+field.getModule());
    			if(queryModule != null){
    				try {
    					Field idField ;
    					try{
    						idField = object.getClass().getDeclaredField(field.getIdFieldName());
    					} catch(NoSuchFieldException e){
    						idField = object.getClass().getSuperclass().getDeclaredField(field.getIdFieldName());
    					}
    					idField.setAccessible(true);
    					String id = (String)idField.get(object);
    					if(id != null && !"".equals(id)){
    						String name = queryModule.query(id,object, field);
    						if(name != null ){	//这里只判断null,不做空判断,因为空可能是数据本身值
    							Field nameField ;
    							try{
    								nameField =  object.getClass().getDeclaredField(field.getNameFieldName());
    							} catch(NoSuchFieldException e){
    								nameField = object.getClass().getSuperclass().getDeclaredField(field.getNameFieldName());
    							}
    							nameField.setAccessible(true);
    							nameField.set(object, name);
    						}
    					}
    				} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
    					e.printStackTrace();
    				}
    			}
    		}
    	}
    }
    

      

    6.定义模块处理类

    package com.query.query;
    
    import com.query.entity.QueryFieldEntity;
    
    /**
     * ClassName:QueryModule <br/>
     * Function: 查询具体模块字段接口. <br/>
     * Date:     2017年6月27日 上午11:30:00 <br/>
     * @author   gavin
     * @since    JDK 1.6
     */
    public interface QueryModule {
    	
    	/**
    	 * query:(查询具体模块方法,可以直接拿到id去做相应查询,然后返回). <br/>
    	 * @author gavin
    	 * @param id		id属性的值
    	 * @param object	具体的实体对象
    	 * @param field		反射需要用到的相关属性
    	 * @return
    	 */
    	public String query(String id, Object object, QueryFieldEntity field);
    }
    

      

    package com.query.query.impl;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import com.entity.pub.Dic;
    import com.query.entity.QueryFieldEntity;
    import com.query.query.QueryModule;
    import com.service.pub.impl.DicService;
    
    /**
     * ClassName:QueryModuleOfDic <br/>
     * Function: 字典模块查询服务. <br/>
    
     */
    @Component("queryModuleOfDic") //用于适配器中上下文获取bean
    public class QueryModuleOfDic implements QueryModule {
    	@Autowired
    	private DicService dicService;
    	
    	@Override
    	public String query(String id, Object object, QueryFieldEntity fieldEntity) {
    		String name = null;
    		if(id != null && !"".equals(id)){
    			Dic dic = dicService.get(id);	//根据id查询字典值
    			if(dic != null){
    				name = dic.getName();
    			}
    		}
    		return name;
    	}
    }
    

      

    7.定义查询切面类  

    import org.apache.log4j.Logger;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import com.annotation.QueryAuto;
    import com.query.query.Query;
    
    /**
     * ClassName:QueryAop <br/>
     * Function: 自动查询切面类. <br/>
     */
    @Aspect
    @Component
    public class QueryAop {
    	@Autowired
    	private Query query;
    	
    	private static final Logger LOG = Logger.getLogger(QueryAop.class);
    	
    	//execution为执行的意思,*代表任意返回值,然后是包名,.*意思是包下面的所有子包 *(..)代表各种方法.  &&  @annotation(queryAuto) 表示并且方法上有为queryAuto的注解
    	@Pointcut(value="execution(* com.service..*.*(..)) && @annotation(queryAuto) " , argNames="queryAuto")
        private void queryAuto(QueryAuto queryAuto){}//定义流程切入点 
    	
    	/**
    	 * queryAuto:(自动查询切面方法). <br/>
    	 * @author gavin
    	 * @param point
    	 * @param queryAuto
    	 * @return
    	 * @throws Throwable
    	 */
    	@Around(value = "queryAuto(queryAuto)" , argNames="queryAuto")
        public Object queryAuto(ProceedingJoinPoint point,QueryAuto queryAuto) throws Throwable {
    		long start = System.currentTimeMillis();
            System.out.println("QueryAuto--->进入自动查询AOP");
            LOG.info("QueryAuto--->进入自动查询AOP");
            
            Object object = point.proceed();//执行方法
            if(object != null){
            	if(object instanceof com.talkweb.common.Page){	//返回类型为page对象
            		query.doPage(object);
            	} else if(object instanceof java.util.List){	//返回类型为List
            		query.doList(object);
            	} else if(object instanceof java.util.Map){		//返回类型为Map
            		//map 不作处理
            	} else if(object.getClass().getName().indexOf("com.talkweb.entity") >=0 ){	//默认为系统业务实体对象,如果为其他的比如:String Integer...基础数据类型,不作处理
            		query.doObject(object);
            	}
            }
            System.out.println("QueryAuto--->退出自动查询AOP方法。方法执行时长: "+ (System.currentTimeMillis() - start) + "ms");
            LOG.info("QueryAuto--->退出自动查询AOP方法。方法执行时长: "+ (System.currentTimeMillis() - start) + "ms");
            return object;
    	}
    }
    

      

    8.使用

    1.在实体类中定义查询字段

    @QueryField(module=QueryConstant.MODULE_AssumeComPany,nameField="fill_park_name")
    private String fill_park_pid;	//填报所在园区,当前填报人所在的园区
    private String fill_park_name;
    

      

    2.在service类中添加自动查询注解

    @QueryAuto
    	@Override
    	public Page<NatureMainEntity> list(int pageNum, int pageSize, Map<String, Object> parameter) {
    		PageHelper.startPage(pageNum, pageSize, pageNum == 0 ? false : true);
    		List<NatureMainEntity> reuslt = getDao().list(parameter);
    		Page<NatureMainEntity> page = new Page<NatureMainEntity>(reuslt);
    		return page;
    	}
    

      

     

  • 相关阅读:
    js原始数据类型和引用数据类型=>callback数据传输原理
    wamp虚拟服务器
    chrome 跨域设置-(完善博客内容)
    js原生API----查找dom
    正则表达式
    ajax ----进度条的原理
    ajax 原理----初级篇
    转载 webstrom识别 React语法
    javascript性能优化
    JavaScript DOM
  • 原文地址:https://www.cnblogs.com/L-zh/p/10445078.html
Copyright © 2011-2022 走看看