注解五:字段翻译(注解+反射+动态属性)
Posted root_zhb
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了注解五:字段翻译(注解+反射+动态属性)相关的知识,希望对你有一定的参考价值。
字段翻译
0、需求
实现字段的自动翻译功能,例如sex=1表示男,region="1"表示国外。
在发送请求之后,将原本的字段和翻译字段都返回给前端。
例如:存在实体Payment,属性只包括(id、serial、region、sex)
调用接口时,自动返回如下内容,sexMeaning 和 regionMeaning
1、POM
其他POM如:jdbc、web、boot不列出来
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>3.2.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
2、entity、controller、service、dao、mapper
2.1、entity
public class Payment implements Serializable
private Long id;
private String serial;
@TestAnnotation(renderers = RegionRender.class)
private String region="1";
@TestAnnotation(renderers = GenderRenderer.class)
private Integer sex=1;
public Integer getSex()
return sex;
public void setSex(Integer sex)
this.sex = sex;
public Long getId()
return id;
public void setId(Long id)
this.id = id;
public String getSerial()
return serial;
public void setSerial(String serial)
this.serial = serial;
public String getRegion()
return region;
public void setRegion(String region)
this.region = region;
@Override
public String toString()
return JSON.toJSONString(this);
2.2、controller
@RestController
public class PaymentController
@Resource
private PaymentService paymentService;
@PostMapping(value = "/payment/create")
public Payment create(@RequestBody Payment payment)
return paymentService.create(payment);
2.3、service
public interface PaymentService
Payment create(Payment payment);
@Service
public class PaymentServiceImpl implements PaymentService
@Resource
private PaymentDao paymentDao;
@Override
public Payment create(Payment payment)
paymentDao.create(payment);
// payment.setSex(0);
return payment;
2.4、dao
@Mapper
public interface PaymentDao
int create(Payment payment);
2.5、mapper
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.zhb.dao.PaymentDao">
<insert id="create" parameterType="com.zhb.entity.Payment" useGeneratedKeys="true" keyProperty="id">
insert into payment(serial) values(#serial);
</insert>
</mapper>
3、render(注解、接口、实现类)
3.1、注解@TestAnnotation
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAnnotation
Class<? extends ValueRenderer>[] renderers() default ;
3.2、接口ValueRenderer
public interface ValueRenderer
Object render(Object value, Object data);
3.3、RegionRender
public class RegionRender implements ValueRenderer
@Override
public Object render(Object value, Object data)
if (value instanceof String)
String flag = (String) value;
if ("0".equals(flag))
return "国内";
return "国外";
return value;
3.4、GenderRenderer
public class GenderRenderer implements ValueRenderer
@Override
public Object render(Object value, Object data)
if (value instanceof Integer)
Integer longTermFlag = (Integer) value;
if (Integer.valueOf(1).equals(longTermFlag))
return "男";
return "女";
return value;
4、aspect
@Aspect
@Component
public class PaymentAspect
private static final Logger logger = LoggerFactory.getLogger(PaymentAspect.class);
@Around(
value = "execution(* com.zhb.service.impl.PaymentServiceImpl.create(..))"
)
@SuppressWarnings("unchecked")
public Object userInsert(ProceedingJoinPoint joinPoint)
Object render=null;
try
Object result= joinPoint.proceed();
logger.info("调用" + joinPoint.getTarget() + "的" + joinPoint.getSignature().getName()
+ "方法。方法返回值:" + result);
render = RenderUtil.render(result.getClass(), result);
catch (Throwable e)
logger.error(joinPoint.getSignature().getName() + "方法发生异常:" + e);
finally
logger.info(joinPoint.getSignature().getName() + "方法结束执行。");
return render;
5、utils
5.1、RenderUtil
public class RenderUtil
public static Object render(Class clazz,Object object) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException
Field[] fields = clazz.getDeclaredFields();
String s = null;
Map<String, Object> addProperties = new HashMap();
Object target=null;
for(int i=0;i< fields.length;i++)
if(fields[i].isAnnotationPresent(TestAnnotation.class))
TestAnnotation annotation = fields[i].getAnnotation(TestAnnotation.class);
System.out.println("field内容是"+fields[i]);
List<Class<? extends ValueRenderer>> renderList=new ArrayList<>();
for(int c=0;c<annotation.renderers().length;c++)
renderList.add(annotation.renderers()[c]);
System.out.println(annotation.renderers()[c]);
//获取方法的索引 例如 public java.lang.Integer annotion2.TestAnnotationService.test
int index=fields[i].toString().lastIndexOf(".")+1;
//根据索引截取具体的方法
String methodString =fields[i].toString().substring(index);
//将方法的首字母大写
String methodString1 = toUpperFirstCharacter(methodString);
//根据反射获取方法字段值,根据get方法获取
Method getTest = clazz.getDeclaredMethod("get"+methodString1);
Object invoke = getTest.invoke(object);
//调用具体的方法,可能有多个注解的处理
for(Class<? extends ValueRenderer> render:renderList)
String render1 = (String)render.getMethod("render", Object.class, Object.class).invoke(render.newInstance(), invoke, null);
System.out.println(render1);
addProperties.put(methodString+"Meaning",render1);
target = ReflectUtil.getTarget(object, addProperties);
return target;
/**
* 将字符串的首字母转大写
* @param s
* @return
*/
private static String toUpperFirstCharacter(String s)
// 利用ascii编码的前移,效率要高于截取字符串进行转换的操作
char[] cs = s.toCharArray();
if (Character.isLowerCase(cs[0]))
cs[0] -= 32;
return String.valueOf(cs);
return s;
5.2、ReflectUtil
使用cglib动态生成类与使用 commons-beanutils获取源对象属性-类型集合,封装成新对象并设置值
public class ReflectUtil
static Logger logger = LoggerFactory.getLogger(ReflectUtil.class);
public static Object getTarget(Object dest, Map<String, Object> addProperties)
// get property map
PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(dest);
Map<String, Class> propertyMap = Maps.newHashMap();
for (PropertyDescriptor d : descriptors)
if (!"class".equalsIgnoreCase(d.getName()))
propertyMap.put(d.getName(), d.getPropertyType());
// add extra properties
addProperties.forEach((k, v) -> propertyMap.put(k, v.getClass()));
// new dynamic bean
DynamicBean dynamicBean = new DynamicBean(dest.getClass(), propertyMap);
// add old value
propertyMap.forEach((k, v) ->
try
// filter extra properties
if (!addProperties.containsKey(k))
dynamicBean.setValue(k, propertyUtilsBean.getNestedProperty(dest, k));
catch (Exception e)
logger.error(e.getMessage(), e);
);
// add extra value
addProperties.forEach((k, v) ->
try
dynamicBean.setValue(k, v);
catch (Exception e)
logger.error(e.getMessage(), e);
);
Object target = dynamicBean.getTarget();
return target;
public static class DynamicBean
/**
* 目标对象
*/
private Object target;
/**
* 属性集合
*/
private BeanMap beanMap;
public DynamicBean(Class superclass, Map<String, Class> propertyMap)
this.target = generateBean(superclass, propertyMap);
this.beanMap = BeanMap.create(this.target);
/**
* bean 添加属性和值
*
* @param property
* @param value
*/
public void setValue(String property, Object value)
beanMap.put(property, value);
/**
* 获取属性值
*
* @param property
* @return
*/
public Object getValue(String property)
return beanMap.get(property);
/**
* 获取对象
*
* @return
*/
public Object getTarget()
return this.target;
/**
* 根据属性生成对象
*
* @param superclass
* @param propertyMap
* @return
*/
private Object generateBean(Class superclass, Map<String, Class> propertyMap)
BeanGenerator generator = new BeanGenerator();
if (null != superclass)
generator.setSuperclass(superclass);
以上是关于注解五:字段翻译(注解+反射+动态属性)的主要内容,如果未能解决你的问题,请参考以下文章