转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
实现步骤:
获取所有的代理类
/**
* 获取应用包名下某父类(接口)的所有子类(或实现类)
* @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<代理类,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);