注解五:字段翻译(注解+反射+动态属性)

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);
            
           

以上是关于注解五:字段翻译(注解+反射+动态属性)的主要内容,如果未能解决你的问题,请参考以下文章

Java语法之反射

熬夜刚完的注解与反射

Java反射和注解基础

注解+反射+递归动态生成多层XML

java注解使用java获取注解的属性获取注解的字段值

java_day21_反射和注解