java mongodb id自增长_Spring-Data-MongoDB如何自定义id生成规则以及id自增示例

本文介绍如何在Spring Data MongoDB中自定义ID生成规则,通过AOP注解方式实现在`onBeforeConvert`时触发ID生成。示例中,自定义ID规则为年月日+序号,如:2017112801。代码示例展示了实体类、自定义注解、生成规则类和事件监听类的实现细节。
摘要由CSDN通过智能技术生成

MongoDB默认的ObjectId确实有其积极意义,但是有时候需求却需要我们自定义id生成规则。

本文使用AOP注解的方式来实现id的自定义规则。

如果声明在id字段上,那它就是自定义的id。也可以声明在其他字段上,与ObjectId并存。

本文由作者三汪首发于简书。

原理分析

Spring Data MongoDB是有生命周期的。通过继承org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener类来实现监听。

本文中产生id的动作在监听到onBeforeConvert时触发。

7个生命周期列举如下:

onBeforeConvert,onBeforeSave,onAfterSave,onAfterLoad,onAfterConvert,onAfterDelete,onBeforeDelete

通过自定义注解标识根据自定义规则赋值的字段。通过org.springframework.util.ReflectionUtils提供的反射功能来获取被自定义注解标识的字段

实现根据数据库中已存在的id生成新的id(自增),使用单例控制并发。

示例

注意:

本例中自定义的id规则为:年月日+序号。如:2017112801,2017112899

示例中没有对自定义id的长度做控制。因此会出现20171128100的情况。

如果需要做控制,请自行在保存方法中做校验。

本文中自定义id的类型为String。

根据所参考的博文作者的说法,自增ID的类型不能定义成Long这种包装类。

Mongotemplate的源码里面对主键ID的类型有限制。只能定义为原生类型。

代码:

ProjectDomain.java(实体类)

(@ProjectCode即本例中自定义的注解。)

(@Getter @Setter @NoArgsConstructor是Lombok提供的注解。如有疑问请自行查阅Lombok相关知识)

(@ApiModelProperty是Swagger提供的注解。如果未使用Swagger请忽略)

@Document

@Getter

@Setter

@NoArgsConstructor

public class ProjectDomain {

@Id

@ProjectCode

@ApiModelProperty(value = "项目编号")

private String code;//code字段在数据库中还是会以_id的名字存在

@ApiModelProperty(value = "项目名称")

@Field(value="name")

private String name;

//其余字段略

}

ProjectCode.java(自定义注解类)

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ProjectCode {

}

CreateProjectCode.java( 生成规则定义和实际生成在此类中)

import java.time.LocalDate;

import java.time.format.DateTimeFormatter;

import java.util.List;

import org.springframework.data.domain.Sort;

import org.springframework.data.domain.Sort.Direction;

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.stereotype.Component;

import com.wolfgy.demo.domain.ProjectDomain;

@Component

class CreateProjectCode {

private static CreateProjectCode createProjectCode = null;

private CreateProjectCode(){}

static synchronized CreateProjectCode getInstance(){

if(createProjectCode == null){

synchronized (CreateProjectCode.class) {

if(createProjectCode == null){

createProjectCode = new CreateProjectCode();

}

}

}

return createProjectCode;

}

synchronized String createProjectCode(MongoTemplate template){

LocalDate date = LocalDate.now();

DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMdd");

String dateStr = date.format(fmt);

Query query = new Query(Criteria.where("code").regex(dateStr+"\\d*")).with(new Sort(Direction.DESC,"code"));

List list = template.find(query, ProjectDomain.class);

if (list != null && !list.isEmpty()) {

String numStr = list.get(0).getCode().substring(8);

Integer numInteger = new Integer(numStr);

int num = numInteger.intValue();

return dateStr+( ++num<10 ? "0"+num : num );

}else{

return dateStr+"01";

}

}

}

SaveEventListener.java(事件监听类)

import java.lang.reflect.Field;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.data.mongodb.core.MongoTemplate;

import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener;

import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent;

import org.springframework.stereotype.Component;

import org.springframework.util.ReflectionUtils;

import com.wolfgy.demo.domain.ProjectDomain;

@Component

public class SaveEventListener extends AbstractMongoEventListener{

@Autowired

private MongoTemplate template;

@Override

public void onBeforeConvert(BeforeConvertEvent event) {

final Object source = event.getSource();

if (source != null) {

ReflectionUtils.doWithFields(source.getClass(), new ReflectionUtils.FieldCallback() {

@Override

public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

ReflectionUtils.makeAccessible(field);

if (field.isAnnotationPresent(ProjectCode.class)) {//判断字段是否被自定义注解标识

field.set(source,CreateProjectCode.getInstance().createProjectCode(template));//设置id

}

}

});

}

}

}

参考内容

以上。

希望我的文章对你能有所帮助。

我不能保证文中所有说法的百分百正确,

但我能保证它们都是我的理解和感悟以及拒绝直接复制黏贴(确实需要引用的部分我会附上源地址)。

有什么意见、见解或疑惑,欢迎留言讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值