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
* Function: 模块关联查询注解
用于返回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
* Function: 模块关联查询注解
* 比如字典数据,我们表里面都存的字典id,之前的开发模式是在业务模块的sql里各种left join去查询字典名称.
* 现在的做法是在实体对象的字典id属性上加上此注解,并写上字典名称属性,会自动去查询数据库,赋值于字典名称属性上去.
*/
@Documented
@Inherited
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface QueryField {
/**
* module:(业务模块编码,默认为Dic 字典模块,其他模块的话需要遵循一定的命名规则,
* 详见com.talkweb.query.common.QueryConstant 模块定义常量).
* @author gavin
* @return
*/
public String module() default "Dic";
/**
* nameField:(字典数据名称属性字段).
* @author gavin
* @return
*/
public String nameField();
}
2.定义自动查询的属性实体类
import java.io.Serializable;
/**
* ClassName:QueryFieldEntity
* Function: 需要自动查询的字段属性对象.
*/
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
* Function: 自动查询工具类.
*/
public class QueryUtil {
/**
* getQueryAutoField:(得到对象中需要自动查询的字段).
* @author gavin
* @param object
* @return
*/
public static List getQueryAutoField(Object object){
List list = new ArrayList();
Class> cls = object.getClass();
Field[] fields = cls.getDeclaredFields();
List fieldList = new ArrayList(Arrays.asList(fields));
//获取父类字段
Class> supercls = cls.getSuperclass();
Field[] superfields = supercls.getDeclaredFields();
fieldList.addAll( new ArrayList(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:(得到对象中需要自动查询的字段).
* @author gavin
* @param object
* @return
*/
public static List getSuperQueryAutoField(Object object){
List list = new ArrayList();
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
* Function: TODO ADD FUNCTION.
* Date: 2017年6月27日 上午9:47:04
*/
public interface Query {
/**
* doPage:(处理分页数据).
* @author gavin
* @param object
*/
public void doPage(Object object);
/**
* doList:(处理简单列表数据).
* @author gavin
* @param object
*/
public void doList(Object object);
/**
* doObject:(处理简单实体对象数据).
* @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
* Function: 自动查询实现类.
* Date: 2017年6月27日 上午9:54:02
* @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 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 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 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
* Function: 自动查询适配器.
*/
@Component("queryAdapter")
public class QueryAdapter {
/**
* handle:(根据不同模块,适配不同的接口实现类处理查询).
* @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
* Function: 查询具体模块字段接口.
* Date: 2017年6月27日 上午11:30:00
* @author gavin
* @since JDK 1.6
*/
public interface QueryModule {
/**
* query:(查询具体模块方法,可以直接拿到id去做相应查询,然后返回).
* @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
* Function: 字典模块查询服务.
*/
@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
* Function: 自动查询切面类.
*/
@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:(自动查询切面方法).
* @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 list(int pageNum, int pageSize, Map parameter) {
PageHelper.startPage(pageNum, pageSize, pageNum == 0 ? false : true);
List reuslt = getDao().list(parameter);
Page page = new Page(reuslt);
return page;
}