java后台设计的思考:使用反射代理所有的后台操作

  我想自己大概是发春期又到了,确实在夜深人静的时候想找人倾诉!  倾诉自己的担忧,分享自己的喜与乐。不知道这是因为什么,也许是看了教父之后,让我对人生有了一些重新的思考。 再坚强的人也有脆弱的时候,所有的坚强都是为了要保护的人,包括保护自己。  抑或许,只是自己年龄到了,荷尔蒙的作用使自己希望寻找到一个伴侣。anyway, 此时此刻,我还是决定继续学习总结,这让自己多少有一些安全感。

   如题,这是自己曾经的一次练习实践。目的是为了减少冗余代码,最后希望达到的效果是,我们只需要写上自己的服务器路径以及定义好自己的数据源标准,便可以实现一个后台服务的效果。 

包结构:(每个包的名字正是它所担任的逻辑角色)。 

通常我们做开发时,需要完成四个垂直逻辑分层: 实体,持久层,业务层,控制层。

   实体的主要作用是对客观事物的抽象,也是整个过程的根本。 它还有一个任务就是与数据库中的持久化实体进行映射。 为了完成这个数据库映射任务,hibernate和mybatis提供了很好的支持。 我才用的是基于hibernate注解的实现方式。 因为hibernate是data-jpa的标准实现。

    它的代码构成是这样的:

package com.automannn.mainBottomItem.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class MainBottomItem{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String iconUrl;
    private String text;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public MainBottomItem() {
    }

    public String getIconUrl() {
        return iconUrl;
    }

    public void setIconUrl(String iconUrl) {
        this.iconUrl = iconUrl;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

  之所以很便捷,是因为它对很多的属性都具有默认的配置,而这些默认配置在我们对数据属性要求不是特别严格时,通常都是适用的。

  hibernate作为jpa标准实现的一个重大特点是,一种叫做jpql的查询实现。 这使得我们可以简化很多的代码操作。 当我使用了datajpa之后,整个持久层的构成代码如下:

package com.automannn.mainBottomItem.dao;

import com.automannn.mainBottomItem.entity.MainBottomItem;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * @author automannn@163.com
 * @time 2018/11/3 17:30
 */
public interface BottomItemDao extends JpaRepository<MainBottomItem,Integer> {

}

   实体和持久层采用jpa标准实现,在整个四层之中,已经有两层的代码被自动完成了。  但是仍然有两层的代码任然需要我们处理。 并且通常业务层的代码是最多,也最复杂。 但是尽管如此,任然存在大量相似的逻辑。  这几个层之间的通信也会因为实体标准的不同而各自不同。  因此首先要做的是统一标准。

   控制层与业务层的交互通过统一的标准: dto对象进行通信。

package com.automannn.mainBottomItem.dto;


import java.util.List;

/**
 * @author automannn@163.com
 * @time 2018/10/21 20:33
 */
public abstract class BaseDto<T> {
   protected T data;

   protected List<T> dataList;

   protected DtoInfo dtoInfo;

   public BaseDto(DtoInfo dtoInfo) {
        this.dtoInfo = dtoInfo;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public List<T> getDataList() {
        return dataList;
    }

    public void setDataList(List<T> dataList) {
        this.dataList = dataList;
    }

    public DtoInfo getDtoInfo() {
        return dtoInfo;
    }

    public void setDtoInfo(DtoInfo dtoInfo) {
        this.dtoInfo = dtoInfo;
    }
}
package com.automannn.mainBottomItem.dto;

/**
 * @author automannn@163.com
 * @time 2018/10/22 14:12
 */
public enum DtoInfo {

    SUCCESS(200,"成功"),
    ERROR(1000,"失败");

    private int state;

    private String message;

    DtoInfo(int state, String message){
        this.state=state;
        this.message=message;
    }

    public int getState() {
        return state;
    }

    public String getMessage() {
        return message;
    }
}

  这就使得有了一个比较固定的逻辑抽象: DTO,DAO,ENTITY。   业务层操作dao,返回dto,entity在整个层间作为dto的内部对象。

  于是可以将业务层的代码通过aop拦截实现,它的实现是这样的:

package com.automannn.meimeijiong.going.service;

import com.automannn.meimeijiong.going.dto.BaseDto;
import org.springframework.data.domain.Pageable;

/**
 * @author automannn@163.com
 * @time 2018/10/24 16:02
 */
public interface IBaseService<T,S extends BaseDto<T>> {
    S add(T t,S s);
    S update(T t,S s);
    S delete(T t,S s);
    S queryOne(T t,S s);
    S queryList(T t, S s);
}
package com.automannn.meimeijiong.going.service.impl;

import com.automannn.meimeijiong.going.dao.LvpaiDao;
import com.automannn.meimeijiong.going.dao.LvpaiRoleDao;
import com.automannn.meimeijiong.going.dto.LvpaiDto;
import com.automannn.meimeijiong.going.entity.Lvpai;
import com.automannn.meimeijiong.going.service.ILvpaiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author automannn@163.com
 * @time 2018/10/25 0:33
 */
@Service
public class LvpaiServiceImpl implements ILvpaiService {

    @Autowired
    LvpaiDao dao;
    @Override
    public LvpaiDto add(Lvpai lvpai, LvpaiDto lvpaiDto) { return null; }

    @Override
    public LvpaiDto update(Lvpai lvpai, LvpaiDto lvpaiDto) {
        return null;
    }

    @Override
    public LvpaiDto delete(Lvpai lvpai, LvpaiDto lvpaiDto) {
        return null;
    }

    @Override
    public LvpaiDto queryOne(Lvpai lvpai, LvpaiDto lvpaiDto) {
        return null;
    }

    @Override
    public LvpaiDto queryList(Lvpai lvpai, LvpaiDto lvpaiDto) {
        return null;
    }
}

它的拦截:

package com.automannn.meimeijiong.going.templateImplProxy;

import com.automannn.meimeijiong.going.dto.BaseDto;
import com.automannn.meimeijiong.going.dto.DtoInfo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;

/**
 * @author automannn@163.com
 * @time 2018/10/24 17:42
 */
@Component
@Aspect
public class AspectServiceImplInterceptor {

    private static String METHOD_NAME=null;
    private static BaseDto DTO =null;
    private static Object ENEITY=null;
    private static JpaRepository DAO=null;

    @Around("execution(* com.automannn.meimeijiong.going.service.impl.*.add*(..))||" +
            "execution(* com.automannn.meimeijiong.going.service.impl.*.update*(..))||" +
            "execution(* com.automannn.meimeijiong.going.service.impl.*.delete*(..))||" +
            "execution(* com.automannn.meimeijiong.going.service.impl.*.query*(..))")
    public Object doImpl(ProceedingJoinPoint pjp) throws NoSuchFieldException, IllegalAccessException {
        Signature signature = pjp.getSignature();
        METHOD_NAME= signature.getName();
        Object[] args= pjp.getArgs();
        ENEITY=args[0];
        DTO = (BaseDto) args[1];

        Class clazz = pjp.getTarget().getClass();

       Field field= clazz.getDeclaredField("dao");
       field.setAccessible(true);
        DAO= (JpaRepository) field.get(pjp.getTarget());

        Object target =null;
        if ("add".equals(METHOD_NAME)){
           target= doAddLogic(ENEITY, DTO,DAO);
        }else if ("update".equals(METHOD_NAME)){
            target= doUpdateLogic(ENEITY, DTO,DAO);
        }else if ("delete".equals(METHOD_NAME)){
            target= doDeleteLogic(ENEITY, DTO,DAO);
        }else if ("queryOne".equals(METHOD_NAME)){
            target=doQueryOneLogic(ENEITY, DTO,DAO);
        }else {
            target=doQueryListLogic(ENEITY, DTO,DAO);
        }
        return target;

    }

    private Object doAddLogic(Object entity,BaseDto returnValue,JpaRepository dao){
        Object saveCallbackBean= dao.save(entity);
        if (!isIdExisted(saveCallbackBean)){
            returnValue.setDtoInfo(DtoInfo.ERROR);
        }else {
            returnValue.setDtoInfo(DtoInfo.SUCCESS);
            returnValue.setData(saveCallbackBean);
        }

        return returnValue;
    }



    private Object doUpdateLogic(Object entity,BaseDto returnValue,JpaRepository dao){
        if (!isIdExisted(entity)){
            returnValue.setDtoInfo(DtoInfo.ERROR);
            return returnValue;
        }
        Object saveCallbackBean=dao.save(entity);
        returnValue.setDtoInfo(DtoInfo.SUCCESS);
        returnValue.setData(saveCallbackBean);

        return returnValue;
    }

    private Object doDeleteLogic(Object entity,BaseDto returnValue,JpaRepository dao){
        if (!isIdExisted(entity)){
            returnValue.setDtoInfo(DtoInfo.ERROR);
            return returnValue;
        }
        dao.delete(entity);
        returnValue.setDtoInfo(DtoInfo.SUCCESS);
        return returnValue;

    }

    private Object doQueryOneLogic(Object entity,BaseDto returnValue,JpaRepository dao){
        Optional optional = dao.findOne(Example.of(entity));
        try {
            Object result = optional.get();
            returnValue.setDtoInfo(DtoInfo.SUCCESS);
            returnValue.setData(result);
        }catch (NoSuchElementException e){
            returnValue.setDtoInfo(DtoInfo.ERROR);
        }
        return returnValue;
    }

    private Object doQueryListLogic(Object entity,BaseDto returnValue,JpaRepository dao){
        List<Object> resultList = dao.findAll(Example.of(entity));
        if (resultList==null){
            returnValue.setDtoInfo(DtoInfo.ERROR);
        }else {
            returnValue.setDtoInfo(DtoInfo.SUCCESS);
            returnValue.setDataList(resultList);
        }

        return returnValue;
    }

    private boolean isIdExisted(Object saveCallbackBean) {
        try {
            Field field = saveCallbackBean.getClass().getDeclaredField("id");
            field.setAccessible(true);
            int id = (int) field.get(saveCallbackBean);
            if (id>0){
                return true;
            }else {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
    }

}

   控制层的代码类似,为了完成控制层的代理,需要将返回的数据类型也统一。  最终,当整个后台系统的重复逻辑越多,代码量越大,那么代理所起到的效果就越大。  如果要完成类似于框架的效果,可以通过配置+策略模式的方式进行扩展。  封装不变,扩展可变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值