在mybatis中自动生成的方法updateByPrimaryKeySelective,表示根据主键修改非Null的属性值,在mongodb中希望实现一个相同的方法
因为可能用2个字段做的联合主键,在mongodb中应该叫唯一索引,所以自定义一个字段注解PrimaryKey

主键注解

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @Author: BillYu
 * @Description:
 * @Date: Created in 09:33 2020-03-09.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface PrimaryKey {
}

在实体类的唯一索引字段加上@PrimaryKey 即可

接口

public interface CustomRepository {
    void updateByIdSelective(Object o, Class clazz);

    /**
     * 根据主键修改不为null的属性值
     * @param o
     * @return
     */
    long updateByPrimaryKeySelective(Object o);
}

实现类

import com.iflytek.voicecloud.yujipc.entity.PrimaryKey;
import com.iflytek.voicecloud.yujipc.repository.CustomRepository;
import com.mongodb.client.result.UpdateResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: BillYu
 * @Description:
 * @Date: Created in 16:09 2019-12-17.
 */
@Service
public class CustomRepositoryImpl implements CustomRepository {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void updateByIdSelective(Object o, Class clazz) {
        clazz = o.getClass();
        String id = null;
        Object idValue = null;
        Field[] fields = LocalStore.filedMap.get(clazz.getName());
        if (fields == null) {
            fields = clazz.getDeclaredFields();
            //添加本地缓存
            LocalStore.filedMap.put(clazz.getName(), fields);
        }
        Update update = new Update();
        //拿到所有的字段,不包括继承的字段
        for (Field field : fields) {
            //设置可访问,不然拿不到private
            field.setAccessible(true);
            //配置了注解的话则使用注解名称,作为header字段
            field.getName();
            try {
                if (StringUtils.isEmpty(id)) {
                    Annotation annotation = field.getAnnotation(Id.class);
                    if (annotation != null) {
                        //主键
                        id = field.getName();
                        idValue = field.get(o);
                    }
                }
                if (!StringUtils.isEmpty(field.getName()) && field.get(o)!=null) {
                    //非空字段 字段名 字段值
                    update.set(field.getName(), field.get(o));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        Query query = new Query();
        Criteria criteria = Criteria.where("_id").is(idValue);
        query.addCriteria(criteria);
        mongoTemplate.updateFirst(query, update, clazz);
    }

    @Override
    public long updateByPrimaryKeySelective(Object o) {
        Class clazz = o.getClass();
        Field[] fields = LocalStore.filedMap.get(clazz.getName());
        if (fields == null) {
            fields = clazz.getDeclaredFields();
            //添加本地缓存
            LocalStore.filedMap.put(clazz.getName(), fields);
        }
        Update update = new Update();
        //拿到所有的字段,不包括继承的字段
        List<Field> keyFields = new ArrayList<>();
        for (Field field : fields) {
            //设置可访问,不然拿不到private
            field.setAccessible(true);
            Annotation annotation = field.getAnnotation(PrimaryKey.class);
            if (annotation != null) {
                //主键
                keyFields.add(field);
            }
            //配置了注解的话则使用注解名称,作为header字段
            try {
                if (!StringUtils.isEmpty(field.getName()) && field.get(o)!=null) {
                    //非空字段 字段名 字段值
                    update.set(field.getName(), field.get(o));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        Criteria criteria = null;
        for (Field field : keyFields) {
            //关注索引顺序
            try {
                if (criteria == null) {

                    criteria = Criteria.where(field.getName()).is(field.get(o));

                } else {
                    criteria.and(field.getName()).is(field.get(o));
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        Query query = new Query();
        query.addCriteria(criteria);
        UpdateResult updateResult = mongoTemplate.updateFirst(query, update, clazz);
        return updateResult.getModifiedCount();
    }
}

在repository中继承CustomRepository 即可使用

public interface UserRepository  extends MongoRepository<User, ObjectId>,CustomRepository {
  
}