SpringBoot系列——Spring-Data-JPA(升级版)

  前言

  在上篇博客中:SpringBoot系列——Spring-Data-JPA:https://www.cnblogs.com/huanzi-qch/p/9970545.html,我们实现了单表的基础get、save(插入/更新)、list、page、delete接口,但是这样每个单表都要写着一套代码,重复而繁杂,那能不能写成一套通用common代码,每个单表去继承从而实现这套基础接口呢?同时,我们应该用Vo去接收、传输数据,实体负责与数据库表映射。

  common代码

  Vo与实体转换

/**
 * 实体转换工具
 */
public class FastCopy {

    /**
     * 类型转换:实体Vo <->实体  例如:UserVo <-> User
     * 支持一级复杂对象复制
     */
    public static <T> T copy(Object src, Class<T> targetType) {
        T target = null;
        try {
            target = targetType.newInstance();
            BeanWrapper targetBean = new BeanWrapperImpl(target);
            BeanMap srcBean = new BeanMap(src);
            for (Object key : srcBean.keySet()) {
                try {
                    String srcPropertyName = key + "";
                    Object srcPropertyVal = srcBean.get(key);
                    //&& StringUtils.isEmpty(targetBean.getPropertyValue(srcPropertyName))
                    if (!StringUtils.isEmpty(srcPropertyVal) && !"class".equals(srcPropertyName)) {
                        Class srcPropertyType = srcBean.getType(srcPropertyName);
                        Class targetPropertyType = targetBean.getPropertyType(srcPropertyName);
                        if (targetPropertyType != null) {
                            if (srcPropertyType == targetPropertyType) {
                                targetBean.setPropertyValue(srcPropertyName, srcPropertyVal);
                            } else {
                                Object targetPropertyVal = targetPropertyType.newInstance();
                                BeanUtils.copyProperties(srcPropertyVal, targetPropertyVal);
                                targetBean.setPropertyValue(srcPropertyName, targetPropertyVal);

                                BeanWrapper targetBean2 = new BeanWrapperImpl(targetPropertyVal);
                                BeanMap srcBean2 = new BeanMap(srcPropertyVal);
                                srcBean2.keySet().forEach((srcPropertyName2) -> {
                                    Class srcPropertyType2 = srcBean2.getType((String) srcPropertyName2);
                                    Class targetPropertyType2 = targetBean2.getPropertyType((String) srcPropertyName2);
                                    if (targetPropertyType2 != null && srcPropertyType2 != targetPropertyType2
                                            && srcBean2.get(srcPropertyName2) != null && !"class".equals(srcPropertyName2)) {
                                        Object targetPropertyVal2 = null;
                                        try {
                                            targetPropertyVal2 = targetPropertyType2.newInstance();
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                        BeanUtils.copyProperties(srcBean2.get(srcPropertyName2), targetPropertyVal2);
                                        targetBean2.setPropertyValue((String) srcPropertyName2, targetPropertyVal2);
                                    }
                                });

                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return target;
    }

    /**
     * 类型转换:实体Vo <->实体  例如:List<UserVo> <-> List<User>
     */
    public static <T> List<T> copyList(List srcList, Class<T> targetType) {
        List<T> newList = new ArrayList<>();
        for (Object entity : srcList) {
            newList.add(copy(entity, targetType));
        }
        return newList;
    }

    /**
     * 获取/过滤对象的空属性
     */
    public static String[] getNullProperties(Object src) {
        BeanWrapper srcBean = new BeanWrapperImpl(src); //1.获取Bean
        Set<String> properties = new HashSet<>(); //3.获取Bean的空属性
        for (PropertyDescriptor p : srcBean.getPropertyDescriptors()) {
            String propertyName = p.getName();
            Object srcValue = srcBean.getPropertyValue(propertyName);
            if (StringUtils.isEmpty(srcValue)) {
                srcBean.setPropertyValue(propertyName, null);
                properties.add(propertyName);
            }
        }
        String[] result = new String[properties.size()];
        return properties.toArray(result);
    }

    /**
     * 获取对象的非空属性
     */
    public static Map<String, Object> getNotNullProperties(Object src) {
        BeanWrapper srcBean = new BeanWrapperImpl(src); //1.获取Bean
        PropertyDescriptor[] pds = srcBean.getPropertyDescriptors(); //2.获取Bean的属性描述
        Map<String, Object> properties = new LinkedHashMap<>();  //3.获取Bean的非空属性
        for (PropertyDescriptor p : pds) {
            String key = p.getName();
            Object value = srcBean.getPropertyValue(key);
            if (!StringUtils.isEmpty(value) && !"class".equals(key)) {
                properties.put(key, value);
            }
        }

        return properties;
    }

    /**
     * 将Object数组转为实体类VO
     */
    public static <V> List<V> getEntityVo(List<Object[]> propertyArrayList, Class<V> voClass) {
        List<V> list = new ArrayList<>();
        try {
            if (propertyArrayList != null) {
                for (Object[] propertyArray : propertyArrayList) {
                    V vo = voClass.newInstance();
                    Field[] fields = vo.getClass().getDeclaredFields();
                    for (int i = 0; i < propertyArray.length; i++) {
                        Field voField = fields[i];
                        Object queryVal = propertyArray[i];
                        if (voField.getType() == String.class && queryVal instanceof BigDecimal) {
                            queryVal = String.valueOf(queryVal);
                        }
                        voField.setAccessible(true);//获取授权
                        voField.set(vo, queryVal);
                    }
                    list.add(vo);
                }

            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return list;
    }

}

  

  通用service、repository

/**
 * 通用Service
 *
 * @param <V> 实体类Vo
 * @param <E> 实体类
 * @param <T> id主键类型
 */
public interface CommonService<V, E,T> {

    Result<PageInfo<V>> page(V entityVo);

    Result<List<V>> list(V entityVo);

    Result<V> get(T id);

    Result<V> save(V entityVo);

    Result<T> delete(T id);
}
/**
 * 通用Service实现类
 *
 * @param <V> 实体类Vo
 * @param <E> 实体类
 * @param <T> id主键类型
 */
public class CommonServiceImpl<V, E, T> implements CommonService<V, E, T> {

    private Class<V> entityVoClass;//实体类Vo

    private Class<E> entityClass;//实体类

    @Autowired
    private CommonRepository<E, T> commonRepository;//注入实体类仓库

    CommonServiceImpl() {
        Type[] types = ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments();
        this.entityVoClass = (Class<V>) types[0];
        this.entityClass = (Class<E>) types[1];
    }

    @Override
    public Result<PageInfo<V>> page(V entityVo) {
        //实体类缺失分页信息
        if (!(entityVo instanceof PageCondition)) {
            throw new RuntimeException("实体类" + entityClass.getName() + "未继承PageCondition。");
        }
        PageCondition pageCondition = (PageCondition) entityVo;
        Page<E> page = commonRepository.findAll(Example.of(FastCopy.copy(entityVo, entityClass)), pageCondition.getPageable());
        return Result.of(PageInfo.of(page, entityVoClass));
    }

    @Override
    public Result<List<V>> list(V entityVo) {
        List<E> entityList = commonRepository.findAll(Example.of(FastCopy.copy(entityVo, entityClass)));
        List<V> entityModelList = FastCopy.copyList(entityList, entityVoClass);
        return Result.of(entityModelList);
    }

    @Override
    public Result<V> get(T id) {
        Optional<E> optionalE = commonRepository.findById(id);
        if (!optionalE.isPresent()) {
            throw new RuntimeException("ID不存在!");
        }
        return Result.of(FastCopy.copy(optionalE.get(), entityVoClass));
    }

    @Override
    public Result<V> save(V entityVo) {
        E e = commonRepository.save(FastCopy.copy(entityVo, entityClass));
        return Result.of(FastCopy.copy(e, entityVoClass));
    }

    @Override
    public Result<T> delete(T id) {
        commonRepository.deleteById(id);
        return Result.of(id);
    }
}
/**
 * 通用Repository
 *
 * @param <E> 实体类
 * @param <T> id主键类型
 */
@NoRepositoryBean
public interface CommonRepository<E,T> extends JpaRepository<E,T>, JpaSpecificationExecutor<E> {
}

  单表使用

  单表继承通用代码,实现get、save(插入/更新)、list、page、delete接口

  Vo

/**
 * 用户类Vo
 */
@Data
public class UserVo extends PageCondition implements Serializable {

    private Integer id;

    private String username;

    private String password;

    private Date created;

    private String descriptionId;

    //机架类型信息
    private DescriptionVo description;
}
/**
 * 用户描述类Vo
 */
@Data
public class DescriptionVo implements Serializable {
    private Integer id;

    private String userId;

    private String description;
}

  controller、service、repository

@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/getAllUser")
    public ModelAndView getAllUser(){
        Result result=userService.getAllUser();
        ModelAndView mv=new ModelAndView();
        mv.addObject("userList",result.getData());
        mv.setViewName("index.html");
        return mv;
    }

    /*
        CRUD、分页、排序
     */

    @RequestMapping("page")
    public Result<PageInfo<UserVo>> page(UserVo entityVo) {
        return userService.page(entityVo);
    }

    @RequestMapping("list")
    public Result<List<UserVo>> list(UserVo entityVo) {
        return userService.list(entityVo);
    }

    @RequestMapping("get/{id}")
    public Result<UserVo> get(@PathVariable("id") Integer id) {
        return userService.get(id);
    }

    @RequestMapping("save")
    public Result<UserVo> save(UserVo entityVo) {
        return userService.save(entityVo);
    }

    @RequestMapping("delete/{id}")
    public Result<Integer> delete(@PathVariable("id") Integer id) {
        return userService.delete(id);
    }
}
public interface UserService extends CommonService<UserVo, User,Integer>{

    Result getAllUser();
}
@Service
public class UserServiceImpl extends CommonServiceImpl<UserVo, User,Integer> implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    public Result getAllUser() {
        List<User> userList = userRepository.getAllUser();
        if(userList != null && userList.size()>0){
            ArrayList<UserVo> userVos = new ArrayList<>();
            for(User user : userList){
                userVos.add(FastCopy.copy(user, UserVo.class));
            }
            return Result.of(userVos);
        }else {
            return Result.of(userList,false,"获取失败!");
        }
    }
}
@Repository
public interface UserRepository extends CommonRepository<User, Integer> {

    @Query(value = "from User") //HQL
//    @Query(value = "select * from tb_user",nativeQuery = true)//原生SQL
    List<User> getAllUser();

}

  经测试,所有的接口都可以使用,数据传输正常,因为传输的Vo,分页信息跟杂七杂八的字段、数据都在Vo,所有看起来会比较杂。更新接口依旧跟上一篇的一样,接收到的是什么就保存什么。

  后记

  单表的增删改查接口,直接继承这一套通用代码即可实现,无需再重复编写,大大提升开发效率。

猜你喜欢

转载自www.cnblogs.com/huanzi-qch/p/9984261.html