JAVA常用编程代码块

Wesley13
• 阅读 743

转Map时要考虑Map的key是否重复

List转为Map<keyField, valueField>

将一个List实体集合转换为以Entity某一个字段为key,另一字段为value映射的Map

/**
     * List转换为Map<key字段,val字段/实体>
     */
    public Map<String,Object> getMapByList(List list){
        Map<String,Object> resultMap= new HashMap<String,Object>();  //结果,字段/值的映射map

        if (CollectionUtil.isNotEmpty(list)){   //先判断list是否为空
            for (Entity entity:list){     //遍历List
                String keyField= entity.getKeyField();   //键
                Object valueField = entity.getValField();   //值,值也可以为其他字段或者整个对象
                /********遍历list的key字段不能直接放入Map中,因为可能有重复的,这样发现不了问题*********/
                if (resultMap.containsKey(keyField)){   //如果key字段的值是有重复的
                    valueField = resultMap.get(keyField) + StringUtil.SEPARATOR + valueField;  //value字段的值为:  旧的数据<-->新的数据作为value
                }                /**********处理可能重复key的情况结束************/
                resultMap.put(keyField,valueField);   //最后在将处理后的keyField和valueField放入到Map中去
            }
        }
        return resultMap;
    }

List转为Map<keyField,List>

将List中的实体根据keyField字段分类成Map<keyField,List>

public Map<String,List<Entity>> getMapByList(List<Entity> list){
        Map<String,List<Entity>> resultMap = new HashMap<String,List<Entity>>();   //目标结果Map

        if (CollectionUtil.isNotEmpty(list)){    //判断是否为空
            for (Entity entity:list){    //遍历List集合
                String keyField = entity.getKeyField();    //获取key字段值
              
                /****************************考虑Map中key值重复的情况*****************************/
                List<Entity> list;   //根据keyField分组的list
                if (resultMap.containsKey(keyField)){    //如果之前有keyField字段对一个的实体已经放入过List,即已经存在在结果Map中
                    list = resultMap.get(keyField);   //根据keyFiedl获取Map中对应的List集合
                }else{
                    list = new ArrayList<Entity>();  //这个字段之前没有放入过实体,没有List,新建一个List
                }
                list.add(entity);   //放入到keyField对应的List中去
                /*************************考虑Map中key值重复的情况结束********************************/
                
                resultMap.put(keyField,list);   //放入到Map<keyField,List<Entity>>的映射中
            }
        }
        return resultMap;
    }

动态代理实现代理链

即当一个class执行某个method方法时,要先执行一系列Proxy(接口)子类的doProxy()方法。

思路:

根据isAssiginFrom获取Proxy所有的实现类,然后根据Proxy子类上的注解获取要拦截哪些类(切点),根据注解获取目标类集合,生成Map<Proxy,Set>

然后转换为Map<targetClass,List>,然后用代理链ProxyChain生成代理链,每当方法执行时,会先执行ProxyChain中的doProxy方法。doProxy方法执行会执行Proxy代理集合(把自己作为参数带进去),然后在Proxy代理实例中继续执行ProxyChain中的doProxy方法,直到所有代理链执行完毕,ProxyChain执行了目标函数,然后依次返回Proxy中执行后续代码。

实现步骤:

获取所有的代理类

/**
     * 获取应用包名下某父类(接口)的所有子类(或实现类)
     * @param superClass 父类/接口/类本身(基本数据类型)
     * @return
     */
    public static Set<Class<?>> getClassSetBySuper(Class<?> superClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        for (Class<?> cls:CLASS_SET){
            /*!!!!!!!!!!重点!!!!!!!!!!获取某个基类的子类(这样可以获取AOP的所有切面)*/
            if (superClass.isAssignableFrom(cls) && !superClass.equals(cls)){  //superClass是cls的父类或接口(superClass为cls的父类/接口/本身 && superClass不等于cls)
                classSet.add(cls);
            }
        }
        return classSet;
    }

获取所有目标类

/**
     * 获取应用包名下带有指定注解的所有类
     * @param annotationClass 注解
     * @return
     */
    public static Set<Class<?>> getClassSetByAnnotation(Class<? extends Annotation> annotationClass){
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        for (Class<?> cls : CLASS_SET){
            if (cls.isAnnotationPresent(annotationClass)){  //如果此类带有annotationClass注解
                classSet.add(cls);
            }
        }
        return classSet;
    }

生成Map<Proxy,Set>

/**
     * 创建所有Map<代理类,Set<代理目标类>>的映射关系
     * @return Map<代理类,Set<代理目标类>>
     * @throws Exception
     */
    private static Map<Class<?>,Set<Class<?>>> createProxyMap() throws Exception{
        Map<Class<?>,Set<Class<?>>> proxyMap = new HashMap<Class<?>, Set<Class<?>>>();   //结果集<代理类,Set<代理目标类>>
        addAspectProxy(proxyMap);   //添加普通切面
        addTransactionProxy(proxyMap);   //添加事务代理
        return proxyMap;
    }

  /**
     * 添加切面代理
     * @param proxyMap
     */
    private static void addAspectProxy(Map<Class<?>,Set<Class<?>>> proxyMap){
        //获取所有的AspectProxy的子类(代理类集合),即切面,
        /*这个是入口,根据基类来查找所有的切面(代理类),获取所有的切面!!!*/
        Set<Class<?>> proxyClassSet = ClassHelper.getClassSetBySuper(AspectProxy.class);
        for (Class<?> proxyClass : proxyClassSet){   //遍历代理类(切面),如ControllerAspect
            if (proxyClass.isAnnotationPresent(Aspect.class)){    //验证基类为AspectProxy且要有Aspect注解的才能为切面。如果代理类的的注解为Aspect(也就是说代理类一定要都切点(注解)才能是切面),例如ControllerAspect代理类的注解为@Aspect(Controller.class)
                Aspect aspect = proxyClass.getAnnotation(Aspect.class);   //获取代理类(切面)的注解
                /*根据注解获取所有的目标类*/
                Set<Class<?>> targetClassSet = createTargetClassSet(aspect);   //获取所有的代理目标类集合
                proxyMap.put(proxyClass,targetClassSet);   //加入到结果集Map<代理类,Set<代理目标类>>中
            }
        }
    }

    /**
     * 根据Aspect注解(切点)获取所有的代理目标类集合(目标类为Controller等注解的类)
     * @param aspect 代理类注解,用来指定目标类的注解 例如:@Aspect(Controller.class)
     * @return 返回Aspect注解中指定value注解的目标类  例如:带Controller注解的所有类
     * 例如Aspect(Controller.class)是指获取所有Controller注解的类
     */
    private static Set<Class<?>> createTargetClassSet(Aspect aspect){
        Set<Class<?>> targetClassSet = new HashSet<Class<?>>();
        Class<? extends Annotation> annotation = aspect.value();   //获取值(也是注解)

if (annotation!=null && !annotation.equals(Aspect.class)){   //获取的value注解不为null,且注解不为Aspect
            targetClassSet.addAll(ClassHelper.getClassSetByAnnotation(annotation));   //加入所有value(切点)指定的注解的类
        }
        return targetClassSet;   //返回所有目标类
    }

然后把Map<Proxy,Set>转成Map<targetClass,List>

/**
     * 将Map<代理类,Set<目标类>> proxyMap转为Map<目标类,List<代理类>> targetMap
     * @param proxyMap Map<代理类,Set<目标类>>
     * @return Map<目标类,List<代理类实例>>
     * @throws Exception
     */
    private static Map<Class<?>,List<Proxy>> createTargetMap(Map<Class<?>,Set<Class<?>>> proxyMap) throws Exception{
        Map<Class<?>,List<Proxy>> targetMap = new HashMap<Class<?>,List<Proxy>>();   //class - list键值对的map
        for (Map.Entry<Class<?>,Set<Class<?>>> proxyEntry:proxyMap.entrySet()){   //遍历cls - set键值对的map
            Class<?> proxyClass = proxyEntry.getKey();   //获取代理cls
            Set<Class<?>> targetClassSet = proxyEntry.getValue();   //获取目标Set
            for (Class<?> targetClass:targetClassSet){    //遍历目标Set
                Proxy proxy = (Proxy) proxyClass.newInstance();   //实例化代理类
                if (targetMap.containsKey(targetClass)){    //如果Map<Class<?>,List<Proxy>>包含该目标类
                    targetMap.get(targetClass).add(proxy);   //直接将代理类添加到对应目标类的Map中
                }else{
                    List<Proxy> proxyList = new ArrayList<Proxy>();   //如果没有
                    proxyList.add(proxy);
                    targetMap.put(targetClass,proxyList);
                }
            }
        }
        return targetMap;
    }

将Map<targetClass,List>生成代理连

static{
        try{
            Map<Class<?>,Set<Class<?>>> proxyMap = createProxyMap();   //获取Map<代理类,Set<目标类>>
            Map<Class<?>,List<Proxy>> targetMap = createTargetMap(proxyMap);  //获取Map<目标类,List<代理实例>>
            for (Map.Entry<Class<?>,List<Proxy>> targetEntry:targetMap.entrySet()){   //遍历Map<目标类,List<代理实例>>
                Class<?> targetClass = targetEntry.getKey();   //目标类
                List<Proxy> proxyList = targetEntry.getValue();    //代理类                //生成代理链!!!
                Object proxy = ProxyManager.createProxy(targetClass,proxyList);   //根据目标类和代理集合创建一个代理
                BeanHelper.setBean(targetClass,proxy);   //将Bean容器中目标类对应的实体替换成代理
            }
        }catch (Exception e){
                LOGGER.error("aop failure",e);
        }
    }

代理链实现如下:

Proxy接口及其实现,这里用到模板方法模式

/**
 * 代理接口
 */
public interface Proxy {

    /**
     * 执行链式代理
     * @param proxyChain 这个链式代理参数中含有所有的代理类,和目标类的参数(类、方法、方法参数)
     * @return
     * @throws Throwable
     */
    Object doProxy(ProxyChain proxyChain) throws Throwable;
}

/**
 * 切面代理
 */
public abstract class AspectProxy implements Proxy{
    private static final Logger logger = LoggerFactory.getLogger(AspectProxy.class);

    /**
     * 执行链式代理
     */
    @Override
    public Object doProxy(ProxyChain proxyChain) throws Throwable {
        Object result = null;
        //获取目标类、方法、方法参数
        Class<?> cls = proxyChain.getTargetClass();
        Method method = proxyChain.getTargetMethod();
        Object[] params = proxyChain.getMethodParams();

        begin();    //代理开始时执行begin方法
        try {
            if (intercept(cls,method,params)){    //判断是否拦截此方法
                before(cls,method,params);     //目标方法执行前代理方法before执行
                result = proxyChain.doProxyChain();   //执行下一个代理
                after(cls,method,result);    //目标方法执行后代理方法after执行
            }else {
                result = proxyChain.doProxyChain();    //执行下一个代理
            }
        }catch(Exception e){
            logger.error("proxy failure",e);
            error(cls,method,params,e);    //抛出异常时代理方法error执行
            throw e;
        }finally{
            end();    //代理结束时执行方法end
        }
        return result;
    }
    /*方法开始前执行*/
    public void begin(){
    }

    /**
     * 拦截
     * @param cls 目标类
     * @param method 目标方法
     * @param params 目标方法参数
     * @return 返回是否拦截
     */
    public boolean intercept(Class<?> cls, Method method, Object[] params) throws Throwable {
        return true;
    }

    /**
     * 前置增强
     * @param cls 目标类
     * @param method 目标方法
     * @param params 目标方法参数
     */
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
    }
    /**
     * 后置增强
     * @param cls 目标类
     * @param method 目标方法
     * @param result 目标方法返回结果
     */
    public void after(Class<?> cls, Method method, Object result) throws Throwable {
    }

    /**
     * 抛出增强
     * @param cls 目标类
     * @param method 目标方法
     * @param params 目标方法参数
     * @param e 异常
     * @throws Throwable
     */
    public void error(Class<?> cls, Method method, Object[] params, Exception e) throws Throwable {
    }
    /*方法结束后执行*/
    public void end(){
    }
}

/**
 * 拦截所有Controller方法
 * 这个切面写在框架里用不了,因为不会加载这个类到CLASS_SET
 */
@Aspect(Controller.class)
public class ControllerAspect extends AspectProxy{
    private static final Logger LOGGER = LoggerFactory.getLogger(ControllerAspect.class);
    private long begin;    //方法开始时间

    /**
     * 前置增强
     * @param cls    目标类
     * @param method 目标方法
     * @param params 目标方法参数
     */
    @Override
    public void before(Class<?> cls, Method method, Object[] params) throws Throwable {
        LOGGER.debug("---------begin---------");
        LOGGER.debug(String.format("class: %s",cls.getName()));
        LOGGER.debug(String.format("method: %s",method.getName()));
        begin = System.currentTimeMillis();
    }

    /**
     * 后置增强
     * @param cls    目标类
     * @param method 目标方法
     * @param result 目标方法返回结果
     */
    @Override
    public void after(Class<?> cls, Method method, Object result) throws Throwable {
        LOGGER.debug(String.format("time: %ds", System.currentTimeMillis()-begin));
        LOGGER.debug("---------end---------");
    }
}

用到的注解

/**
 * 切面注解
 * 用来指定切点为哪些注解
 * Controller这类注解
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Aspect {
    /*值为注解,也就是说切点为指定的注解 -  值为Controller或者Service等注解*/
    Class<? extends Annotation> value();
}

代理链类

/**
 * 代理链
 */
public class ProxyChain {
    private final Class<?> targetClass;    //代理类
    private final Object targetObject;    //目标对象
    private final Method targetMethod;    //目标方法
    private final MethodProxy methodProxy;    //代理方法 - CGLib中参数
    private final Object[] methodParams;    //方法参数

    private List<Proxy> proxyList = new ArrayList<Proxy>();   //代理列表 - 各种代理类 例如ControllerAspect等类
    private int proxyIndex = 0;    //代理索引

    public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, MethodProxy methodProxy, Object[] methodParams, List<Proxy> proxyList) {
        this.targetClass = targetClass;
        this.targetObject = targetObject;
        this.targetMethod = targetMethod;
        this.methodProxy = methodProxy;
        this.methodParams = methodParams;
        this.proxyList = proxyList;
    }

    public Class<?> getTargetClass() {
        return targetClass;
    }

    public Method getTargetMethod() {
        return targetMethod;
    }

    public Object[] getMethodParams() {
        return methodParams;
    }

    /**
     * 调用代理类及目标类
     * 这个比较有意思,通过代理链的实例proxyChain不断调用此方法,每次调用都会拿出list中的一个代理执行doProxy方法(doProxy方法中再用proxyChain实例调用此方法)
     * @return 返回目标类执行的结果
     * @throws Throwable
     */
    public Object doProxyChain() throws Throwable {
        Object methodResult;
        if (proxyIndex<proxyList.size()){   //如果代理索引小于代理列表大小
            //从列表中取出Proxy对象,调用器doProxy方法
            methodResult = proxyList.get(proxyIndex++).doProxy(this);
        }else {    //所有代理遍历完后
            methodResult = methodProxy.invokeSuper(targetObject,methodParams);  //执行目标对象业务
        }
        return methodResult;
    }
}

代理链管理器(生成代理链)

/**
 * 代理管理器
 */
public class ProxyManager {
    /**
     * 根据目标类和代理列表创建一个代理链
     * @param targetClass  目标类
     * @param proxyList  代理列表
     * @param <T> 返回一个代理链执行的返回结果
     * @return
     */
    public static <T> T createProxy(final Class<T> targetClass, final List<Proxy> proxyList){
        return (T) Enhancer.create(targetClass, new MethodInterceptor() {   //方法执行时才会执行此代码块
            @Override
            public Object intercept(Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy) throws Throwable {
                //每个方法执行都会执行性代理链的doProxyChain方法(这里每执行一个目标类的方法,都会new一个代理链并执行该代理链)
                return new ProxyChain(targetClass,targetObject,targetMethod,methodProxy,methodParams,proxyList).doProxyChain();
            }
        });
    }
}

这里Proxy用到了模板方法模式,代理链生成及运行时CGLib起作用的精华。每运行一个方法,都会去调用代理链的doProxy方法,而代理链的doProxy方法中又会根据代理类集合的下标依次调用doProxy方法。

Java对象转Json 

目标Json

var data = [
            ['2016/12/18 6:38:08', 80],
            ['2016/12/18 16:18:18', 60],
            ['2016/12/18 19:18:18', 90]
           ];

Java实现

List<Object[]> data = new LinkedList<Object[]>();
//如果需要多个这样的数据
Map<String, List> resultMap = new HashedMap();
resultMap.put("data", data);
Gson gson = new Gson();
String result = gson.toJson(data);
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
java8新特性
Stream将List转换为Map,使用Collectors.toMap方法进行转换背景:User类,类中分别有id,name,age三个属性。List集合,userList,存储User对象1、指定keyvalue,value是对象中的某个属性值。 Map<Integer,StringuserMap1userList.str
Stella981 Stella981
3年前
HIVE 时间操作函数
日期函数UNIX时间戳转日期函数: from\_unixtime语法:   from\_unixtime(bigint unixtime\, string format\)返回值: string说明: 转化UNIX时间戳(从19700101 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式举例:hive   selec
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这