spring data rest with composite primary key

前端 未结 2 1758
忘了有多久
忘了有多久 2020-12-10 06:51

I use spring data rest for crud. But when the entity has composite primary keys, I dont know how to to get an entity by giving the primary key.

River class:

相关标签:
2条回答
  • 2020-12-10 07:05

    There is a jira issue you can look at: https://jira.spring.io/browse/DATAREST-598

    This comment might be especially interesting for you

    https://jira.spring.io/browse/DATAREST-598?focusedCommentId=117740&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-117740

    There you find also a github link to a sample project. It uses a BackendIdConverter to convert the composite key to string and back. So the trick is to convert your composite id to a string that can be used as the path segment.

    This answer might also be interesting for you https://stackoverflow.com/a/31830586/5371736

    0 讨论(0)
  • 2020-12-10 07:07

    After learn from Customizing HATEOAS link generation for entities with composite ids, I found a much more generic solution.

    First, create a SpringUtil to get bean from spring.

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    import org.springframework.stereotype.Component;
    
    @Component
    public class SpringUtil implements ApplicationContextAware {
        private static ApplicationContext applicationContext;
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            if(SpringUtil.applicationContext == null) {
                SpringUtil.applicationContext = applicationContext;
            }
        }
    
        public static ApplicationContext getApplicationContext() {
            return applicationContext;
        }
    
        public static Object getBean(String name){
            return getApplicationContext().getBean(name);
        }
    
        public static <T> T getBean(Class<T> clazz){
            return getApplicationContext().getBean(clazz);
        }
    
        public static <T> T getBean(String name,Class<T> clazz){
            return getApplicationContext().getBean(name, clazz);
        }
    }
    

    Then, implement BackendIdConverter.

    import com.alibaba.fastjson.JSON;
    import com.example.SpringUtil;
    import org.springframework.data.jpa.repository.JpaRepository;
    import org.springframework.data.rest.webmvc.spi.BackendIdConverter;
    import org.springframework.stereotype.Component;
    
    import javax.persistence.EmbeddedId;
    import javax.persistence.Id;
    import java.io.Serializable;
    import java.io.UnsupportedEncodingException;
    import java.lang.reflect.Method;
    import java.net.URLDecoder;
    import java.net.URLEncoder;
    
    @Component
    public class CustomBackendIdConverter implements BackendIdConverter {
    
        @Override
        public boolean supports(Class<?> delimiter) {
            return true;
        }
    
        @Override
        public Serializable fromRequestId(String id, Class<?> entityType) {
            if (id == null) {
                return null;
            }
    
            //first decode url string
            if (!id.contains(" ") && id.toUpperCase().contains("%7B")) {
                try {
                    id = URLDecoder.decode(id, "UTF-8");
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
    
            //deserialize json string to ID object
            Object idObject = null;
            for (Method method : entityType.getDeclaredMethods()) {
                if (method.isAnnotationPresent(Id.class) || method.isAnnotationPresent(EmbeddedId.class)) {
                    idObject = JSON.parseObject(id, method.getGenericReturnType());
                    break;
                }
            }
    
            //get dao class from spring
            Object daoClass = null;
            try {
                daoClass = SpringUtil.getBean(Class.forName("com.example.db.dao." + entityType.getSimpleName() + "DAO"));
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            //get the entity with given primary key
            JpaRepository simpleJpaRepository = (JpaRepository) daoClass;
            Object entity = simpleJpaRepository.findOne((Serializable) idObject);
            return (Serializable) entity;
    
        }
    
        @Override
        public String toRequestId(Serializable id, Class<?> entityType) {
            if (id == null) {
                return null;
            }
    
            String jsonString = JSON.toJSONString(id);
    
            String encodedString = "";
            try {
                encodedString = URLEncoder.encode(jsonString, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            return encodedString;
        }
    }
    

    After that. you can do what you want.

    There is a sample below.

    • If the entity has single property pk, you can use localhost:8080/demo/1 as normal. According to my code, suppose the pk has annotation "@Id".
    • If the entity has composed pk, suppose the pk is demoId type, and has annotation "@EmbeddedId", you can use localhost:8080/demo/{demoId json} to get/put/delete. And your self link will be the same.
    0 讨论(0)
提交回复
热议问题