当前位置 : 主页 > 编程语言 > java >

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

来源:互联网 收集:自由互联 发布时间:2022-07-07
我想自己大概是发春期又到了,确实在夜深人静的时候想找人倾诉! 倾诉自己的担忧,分享自己的喜与乐。不知道这是因为什么,也许是看了教父之后,让我对人生有了一些重新的思考


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

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

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

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

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

   实体的主要作用是对客观事物的抽象,也是整个过程的根本。 它还有一个任务就是与数据库中的持久化实体进行映射。 为了完成这个数据库映射任务,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;
}
}

}

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

网友评论