首页 > 解决方案 > 使用枚举过滤状态

问题描述

嗨,我有弹簧服务,在存储库中我试图按枚举过滤

List<Organization> findAllByStatus(StatusType type);

由于某种原因,这个枚举参数没有传递给 sql 查询。

where organizati0_.status=?在 SQL 中看到,但没有传递任何参数。

知道可能是什么原因吗?

枚举:

public enum StatusType {
  ACTIVE,
  TO_BE_DELETED,
  @Deprecated IN_ACTIVE
} 

服务:

public List<Organization> getAllOrganizations() {
        return Lists.newArrayList(organizationRepository.findAllByStatus(StatusType.TO_BE_DELETED));
}

标签: spring-bootenumsspring-data-jpaspring-data

解决方案


import java.io.Serializable;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import com.example.demo.jobs.CustomQueryParamMethodInterceptor;

import org.springframework.aop.framework.ProxyFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.RepositoryProxyPostProcessor;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.util.Assert;

public class MyJpaRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable>
        extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {

    private EntityManager entityManager;

    private static final CustomQueryParamMethodInterceptor interceptor = new CustomQueryParamMethodInterceptor();
    /**
     * Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface.
     *
     * @param repositoryInterface must not be {@literal null}.
     */
    public MyJpaRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
    }

    /**
     * The {@link EntityManager} to be used.
     *
     * @param entityManager the entityManager to set
     */
    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#setMappingContext(org.springframework.data.mapping.context.MappingContext)
     */
    @Override
    public void setMappingContext(MappingContext<?, ?> mappingContext) {
        super.setMappingContext(mappingContext);
    }

    /*
     * (non-Javadoc)
     *
     * @see org.springframework.data.repository.support.
     * TransactionalRepositoryFactoryBeanSupport#doCreateRepositoryFactory()
     */
    @Override
    protected RepositoryFactorySupport doCreateRepositoryFactory() {
        RepositoryFactorySupport support = createRepositoryFactory(entityManager);
        support.addRepositoryProxyPostProcessor(new RepositoryProxyPostProcessor() {
            @Override
            public void postProcess(ProxyFactory factory, RepositoryInformation repositoryInformation) {
                factory.addAdvice(interceptor);
            }
        });
        return support;
    }

    /**
     * Returns a {@link RepositoryFactorySupport}.
     *
     * @param entityManager
     * @return
     */
    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        return new JpaRepositoryFactory(entityManager);
    }

    /*
     * (non-Javadoc)
     *
     * @see
     * org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
     */
    @Override
    public void afterPropertiesSet() {

        Assert.notNull(entityManager, "EntityManager must not be null!");
        super.afterPropertiesSet();
    }
}

然后将注释添加到您的spring应用程序类

@EnableJpaRepositories(repositoryFactoryBeanClass = MyJpaRepositoryFactoryBean.class)

并创建一个方法拦截器以将枚举参数转换为特定类型

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;

import com.example.demo.dto.ParamWrapper;
import com.example.demo.dto.StatusType;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.framework.ReflectiveMethodInvocation;

public class CustomQueryParamMethodInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (invocation instanceof ReflectiveMethodInvocation) {
            ReflectiveMethodInvocation rmi = (ReflectiveMethodInvocation)invocation;
            Object[] args = invocation.getArguments();
            if (args != null && args.length > 0) {
                Object[] newArgs = new Object[args.length];
                for (int i=0 ;i<args.length; i++) {
                    if (args[i] instanceof ParamWrapper) {
                        ParamWrapper p = (ParamWrapper)args[i];
                        newArgs[i] = p.getValue();
                    } else {
                        newArgs[i] = args[i];
                    }
                }
                rmi.setArguments(newArgs);
            }
        }
        return invocation.proceed();
    }
}

ParamWrapper 是您的枚举应实现的泛型类型

public interface ParamWrapper<T> {
    T getValue();
}

那么你的枚举应该像这样改变

public enum StatusType implements ParamWrapper<Integer> {
    ACTIVE,
    TO_BE_DELETED,
    @Deprecated IN_ACTIVE;

    @Override
    public Integer getValue() {
        //you should determine your value
        return 1;
    }
}

推荐阅读