spring-data-mongoDB

发布于:2025-02-25 ⋅ 阅读:(9) ⋅ 点赞:(0)

目录

spring-data-mongoDB使用

1.导入mongoDB依赖

2.编写配置文件

3.编写实体类,与mongoDB中的文档相对应,使用@Document注解

4.编写service层方法

一.实现保存方法

 二.实现修改方法

三.实现删除方法

四.实现查询方法

项目使用mongoDB实现作业范围 

1.实体类

2.业务实现


这里介绍以下spring-data-mongoDB的用法

spring-data-mongoDB使用

1.导入mongoDB依赖

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

2.编写配置文件

spring:
  application:
    name: sl-express-mongodb
  data:
    mongodb:
      host: 192.168.150.101
      port: 27017
      database: sl
      authentication-database: admin #认证数据库
      username: sl
      password: "123321"
      auto-index-creation: true #自动创建索引

3.编写实体类,与mongoDB中的文档相对应,使用@Document注解

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexType;
import org.springframework.data.mongodb.core.index.GeoSpatialIndexed;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document("sl_person") //指定表名,也就是指定集合的名字
public class Person {
    @Id // 标识为主键
    private ObjectId id;
    @Indexed //标识索引字段
    private String name;
    private int age;
    /**
     * 用户位置
     * x: 经度,y:纬度
     */
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPoint location;
    //存储嵌套对象数据
    private Address address;
}
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.mongodb.core.mapping.Document;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Document("sl_address") //指定表名,也就是指定集合的名字
public class Address {
    private String street;
    private String city;
    private String zip;
}

4.编写service层方法

因为mongoDB没有向mysql,neo4j一样提供持久层的接口方法,但是和redis一样有一个MongoTemplate 的bean对象,可以直接对数据库进行CRUD操作

public interface PersonService {
    /**
     * 新增数据
     *
     * @param person 数据
     */
    void savePerson(Person person);
    /**
     * 更新数据
     *
     * @param person 数据
     */
    void update(Person person);
    /**
     * 根据名字查询用户列表
     *
     * @param name 用户名字
     * @return 用户列表
     */
    List<Person> queryPersonListByName(String name);
    /**
     * 分页查询用户列表
     *
     * @param page     页数
     * @param pageSize 页面大小
     * @return 用户列表
     */
    List<Person> queryPersonPageList(int page, int pageSize);
    /**
     * 根据id删除用户
     *
     * @param id 主键
     */
    void deleteById(String id);
}
import org.springframework.data.mongodb.core.MongoTemplate;

import javax.annotation.Resource;
import java.util.List;

public class PersonServiceImpl implements PersonService {
    @Resource
    private MongoTemplate mongoTemplate;
    @Override
    public void savePerson(Person person) {

    }

    @Override
    public void update(Person person) {

    }

    @Override
    public List<Person> queryPersonListByName(String name) {
        return null;
    }

    @Override
    public List<Person> queryPersonPageList(int page, int pageSize) {
        return null;
    }

    @Override
    public void deleteById(String id) {

    }
}

一.实现保存方法

可以使用insert方法和save方法,但是save方法会直接覆盖原来的值

  @Override
    public void savePerson(Person person) {
        mongoTemplate.save(person);
    }

测试

import org.bson.types.ObjectId;


 @Resource
    PersonService personService;
    @Test
    void savePerson() {
        Person person = Person.builder()
                .id(ObjectId.get()) //使用mongoDB提供的ObjectId生成id值
                .name("张三")
                .age(20)
                .location(new GeoJsonPoint(116.343847, 40.060539))
                .address(new Address("人民路", "上海市", "666666")).build();
        this.personService.savePerson(person);
    }

不使用ObjectId获取id也可以,mongoDB也会自己生成

@Test
    void savePerson() {
        Person person = Person.builder()
                //.id(ObjectId.get())
                .name("张三")
                .age(20)
                .location(new GeoJsonPoint(116.343847, 40.060539))
                .address(new Address("人民路", "上海市", "666666")).build();
        this.personService.savePerson(person);
    }

 二.实现修改方法

 @Override
    public void update(Person person) {
        //1.构建查询条件,定义要改哪些数据,这里定义了要改主键_id=person.getId的数据
        /*Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(person.getId()));*/
        //或者:
        Query query = Query.query(Criteria.where("_id").is(person.getId()));

        //2.设置要修改的值
        Update update = new Update();
        update.set("name",person.getName());
        update.set("age",person.getAge());
        update.set("location",person.getLocation());
        update.set("address",person.getAddress());
        //3.只修改一个
        mongoTemplate.updateFirst(query,update, Person.class);//根据Person.class提供的类型才能去操作哪一个集合
    }

测试

    @Test
    void update() {
        Person person = Person.builder()
                .id(new ObjectId("67b7fb71ab81697aa2e8688e"))
                .name("张三")
                .age(22) //修改数据
                .location(new GeoJsonPoint(116.343847, 40.060539))
                .address(new Address("人民路", "上海市", "666666")).build();
        this.personService.update(person);
    }

三.实现删除方法

其实_id可以写出id,mongo也会当作主键去查

    @Override
    public void deleteById(String id) {
        Query query = Query.query(Criteria.where("_id").is(id));
        mongoTemplate.remove(query, Person.class);
    }

测试

@Test
    void deleteById() {
        this.personService.deleteById("67b7fb71ab81697aa2e8688e");
    }

四.实现查询方法

    @Override
    public List<Person> queryPersonListByName(String name) {
        Query query = Query.query(Criteria.where("name").regex(name));//根据正则表达式查询,类似模糊查询
        return mongoTemplate.find(query,Person.class);
    }

测试

    @Test
    void queryPersonListByName() {
        List<Person> personList = this.personService.queryPersonListByName("三");
        personList.forEach(System.out::println);
    }

五.实现分页查询

@Override
    public List<Person> queryPersonPageList(int page, int pageSize) {
        //1.构建查询条件
        Query query = new Query();
        //根据age降序
        query.with(Sort.by(Sort.Direction.DESC,"age"));
        //构建分页条件,mongoDB默认页数从0开始,而一般前端都是从第一页,所以要减一
        query.with(PageRequest.of((page-1),pageSize));
        return mongoTemplate.find(query, Person.class);
    }

 测试

    @Test
    void queryPersonPageList() {
        List<Person> personList = this.personService.queryPersonPageList(1, 10);
        personList.forEach(System.out::println);
    }

项目使用mongoDB实现作业范围 

1.实体类

这里对id主键不进行json序列化,使用bid作为我们的业务id,并且对类型进行普通索引,使用type来区分快递机构和快递员,最后使用GeoJsonPolygon类型作为面积范围的闭合的多边形范围,并使用索引

@Data
@Document("sl_service_scope")
public class ServiceScopeEntity {

    @Id
    @JsonIgnore
    private ObjectId id;

    /**
     * 业务id,可以是机构或快递员
     */
    @Indexed
    private Long bid;

    /**
     * 类型 {@link com.sl.ms.scope.enums.ServiceTypeEnum}
     */
    @Indexed
    private Integer type;

    /**
     * 多边形范围,是闭合的范围,开始经纬度与结束经纬度必须一样
     * x: 经度,y:纬度
     */
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private GeoJsonPolygon polygon;

    private Long created; //创建时间
    private Long updated; //更新时间
}
public enum ServiceTypeEnum {

    ORGAN(1, "机构"),
    COURIER(2, "快递员");

    /**
     * 类型编码
     */
    private final Integer code;

    /**
     * 类型值
     */
    private final String value;


    ServiceTypeEnum(Integer code, String value) {
        this.code = code;
        this.value = value;
    }

    public Integer getCode() {
        return code;
    }

    public String getValue() {
        return value;
    }

    public static ServiceTypeEnum codeOf(Integer code) {
        return EnumUtil.getBy(ServiceTypeEnum::getCode, code);
    }
}

2.业务实现

保存数据

/**
     * 保存或修改 作业范围
     * @param bid     业务id
     * @param type    类型
     * @param polygon 多边形坐标点
     * @return
     */
    @Override
    public Boolean saveOrUpdate(Long bid, ServiceTypeEnum type, GeoJsonPolygon polygon) {
        // TODO day08 新增作业范围
        // 1. 构建mongo查询条件  bid    type
        Query query = Query.query(Criteria.where("bid").is(bid).and("type").is(type.getCode()));
        // 2. 根据条件查询对应作业范围
        ServiceScopeEntity serviceScopeEntity = mongoTemplate.findOne(query, ServiceScopeEntity.class);
        // 3. 如果作业范围为空 ==> 新建作业范围保存
        if(ObjectUtil.isEmpty(serviceScopeEntity)){
            serviceScopeEntity=new ServiceScopeEntity();
            serviceScopeEntity.setBid(bid);
            serviceScopeEntity.setType(type.getCode());
            serviceScopeEntity.setPolygon(polygon);
            serviceScopeEntity.setCreated(System.currentTimeMillis());
            serviceScopeEntity.setUpdated(System.currentTimeMillis());
        }else{
            // 4. 如果作业范围存在 ==> 修改多边形字段 和 updated时间
            serviceScopeEntity.setPolygon(polygon);
            serviceScopeEntity.setUpdated(System.currentTimeMillis());
        }
        try {
            mongoTemplate.save(serviceScopeEntity);
            return true;
        } catch (Exception e) {
            log.error("新增或者修改数据失败,{}",serviceScopeEntity);
        }
        // 5. 返回结果
        return false;
    }

 GeoJsonPolygon类型的构造参数使用的是List<Point>,注意第一个节点数据需要与最后一个节点数据一样,因为要保持是闭合的多边形

   import org.springframework.data.geo.Point;
 @Test
    void saveOrUpdate() {
        List<Point> pointList = Arrays.asList(new Point(116.340064,40.061245),
                new Point(116.347081,40.061836),
                new Point(116.34751,40.05842),
                new Point(116.342446,40.058092),
                new Point(116.340064,40.061245));
        Boolean result = this.scopeService.saveOrUpdate(2L, ServiceTypeEnum.ORGAN, new GeoJsonPolygon(pointList));
        System.out.println(result);
    }

 根据传入的一个点的坐标来判断在哪一个机构或者快递员中的范围中,可能会查出来多个,所以用集合

 @Override
    public List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, GeoJsonPoint point) {
        // TODO day08 根据类型 和 坐标点查询有交集的作业范围     tips: intersects 查询传入坐标点和mongo库中多边形相交的数据
        Query query = Query.query(Criteria.where("type").is(type.getCode()).and("polygon").intersects(point));
        return mongoTemplate.find(query, ServiceScopeEntity.class);
    }
    @Override
    public List<ServiceScopeEntity> queryListByPoint(ServiceTypeEnum type, String address) {
        // TODO day08 根据类型 和 详细地址     tips: eagleMapTemplate 查询坐标点
        GeoResult geoResult = eagleMapTemplate.opsForBase().geoCode(address);
        Coordinate location = geoResult.getLocation();
        return queryListByPoint(type,new GeoJsonPoint(location.getLongitude(),location.getLatitude()));
    }
    @Test
    void testQueryListByPoint() {
        GeoJsonPoint point = new GeoJsonPoint(116.344828,40.05911);
        List<ServiceScopeEntity> serviceScopeEntities = this.scopeService.queryListByPoint(ServiceTypeEnum.ORGAN, point);
        serviceScopeEntities.forEach(serviceScopeEntity -> System.out.println(serviceScopeEntity));
    }

    @Test
    void testQueryListByPoint2() {
        String address = "北京市昌平区金燕龙办公楼";
        List<ServiceScopeEntity> serviceScopeEntities = this.scopeService.queryListByPoint(ServiceTypeEnum.ORGAN, address);
        serviceScopeEntities.forEach(serviceScopeEntity -> System.out.println(serviceScopeEntity));
    }

可以发现这个坐标点被这个闭合的多边形包围 

 根据bid和类型查询

    public ServiceScopeEntity queryByBidAndType(Long bid, ServiceTypeEnum type) {
        // TODO day08 根据bid和类型查询作业范围
        Query query = Query.query(Criteria.where("bid").is(bid).and("type").is(type.getCode()));
        return mongoTemplate.findOne(query,ServiceScopeEntity.class);
    }