spring-boot + mongodb 学习使用

原因

	最近项目有使用mongodb,现在短暂告一段后,对spring-boot-starter-data-mongodb 的使用进行一些简单总结

安装mongodb

  如果使用docker 的话 ,docker-compose.yml 如下,没有映射文件到出来,是简单的学习使用。
version: '3'

services:
  mongo:
    image: mongo
    container_name: mongo1
    restart: always
    ports:
      - 27017:27017
 如果是没有使用docker 官网下载

MongoDB Compass MongoDB的GUI ,docker是没有GUI的,如果要看数据的话也要安装这个
MongoDB

简单初始化一个项目

start.spring

添加start

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

spring 提供两种的start
spring-boot-starter-data-mongodb

Starter for using MongoDB document-oriented database and Spring Data MongoDB

spring-boot-starter-data-mongodb-reactive

Starter for using MongoDB document-oriented database and Spring Data MongoDB Reactive

这里我选择第一个,实际上spring-boot-starter-data-mongodb-reactive 功能更强大,之后用到再说。

配置参数


logging:
  level:
    org.springframework.data.mongodb.core: debug
spring:
  data:
    mongodb:
      database: xxx 
      host: 127.0.0.1

注意,如果需要验证的话,需要配置 host,port,username,password,authenticationDatabase
其他还好说, authenticationDatabase 一般是admin, 需要参数如图
在这里插入图片描述

使用Querydsl 和 jpa 的原因

因为之前jpa 和 Querydsl 使用比较熟悉了,用的比较顺手,其次,可以很大程度上减少mongodb  的查询语法的使用。

jpa

简单增删改查

entity
public class Person {

    @Id
    private String id;
    private String name;
    private Integer age;
    

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

添加 Repository

import org.springframework.data.repository.PagingAndSortingRepository;

public interface PersonRepository extends PagingAndSortingRepository<Person, String> {


}
简而言之 ,继承PagingAndSortingRepository, 传入 Person 和 ID 类型 这样其实简单增删改就实现了
简单实现service 层面
public interface PersonService {
    void update(String name, String age);

    Person findById(String id);

    void delete(String id);

    Person save(String name);
}
@Service
public class PersonServiceImpl implements PersonService {

    @Autowired
    private PersonRepository personRepository;

    @Override
    public void update(String name, String age) {

    }

    @Override
    public Person findById(String id) {
        Optional<Person> person = personRepository.findById(id);
        return person.orElse(null);
    }

    @Override
    public void delete(String id) {
         personRepository.deleteById(id);
    }

    @Override
    public Person save(String name) {
        Person person = new Person();
        person.setName(name);
        return personRepository.save(person);
    }
}
 @Service 不要忘记,简单的增删改查已经实现了
 写个简单test
@SpringBootTest
class MongodbApplicationTests {

	@Autowired
	private PersonService personService;

	@Test
	void test1() {
		//保存
		Person save = personService.save("test1");
		System.out.println("save == " + save);
		
		//读取
		Person person = personService.findById(save.getId());
		System.out.println("findById == " + person);

		//删除
		 personService.delete(person.getId());
		System.out.println("delete == ");

		//读取
		Person result = personService.findById(save.getId());
		System.out.println("result == " + result);

	}

}

save == Person{id=‘60cdee828f5b721967a17872’, name=‘test1’, age=null}
findById == Person{id=‘60cdee828f5b721967a17872’, name=‘test1’, age=null}
delete ==
result == null
执行结果
打印下查询日志
findOne using query: { “id” : “60cdee828f5b721967a17872”} fields: Document{{}}
Remove using query: { “_id” : { “$oid” : “60cdee828f5b721967a17872”}}

PersonRepository 里面可以自己定义方法,如果是使用idea Ultimate 版本 会有提示,社区版的话就没有了,不过spring 上面有语法文档
在这里插入图片描述
spring文档

可以实现自定义接口了

public interface PersonRepository extends PagingAndSortingRepository<Person, String> {
    Optional<Person> findFirstByName(String name);
}
 @Override
    public void update(String name, Integer age) {
        Optional<Person> first = personRepository.findFirstByName(name);
        if(first.isPresent()) {
            Person person = first.get();
            person.setAge(age);
            personRepository.save(person);
        }
    }
	@Test
	void test2() {
		//保存
		Person save = personService.save("test2");
		System.out.println("save == " + save);

		//更新
		personService.update("test2", 18);
		System.out.println("update == ");

		//读取
		Person result = personService.findById(save.getId());
		System.out.println("result == " + result);
	}

结果
save == Person{id=‘60cdf3edbbe87d40bdaa32de’, name=‘test2’, age=null}
update ==
result == Person{id=‘60cdf3edbbe87d40bdaa32de’, name=‘test2’, age=18}
看下数据
在这里插入图片描述

分页

    Page<Person> findAllByNameContains(String name, Pageable pageable);

执行语句是
find using query: { “name” : { “$regularExpression” : { “pattern” : “.XXX.”, “options” : “”}}} fields: Document{{}}

    @Override
    public void saveAll(List<Person> persons) {
        personRepository.saveAll(persons);
    }

    @Override
    public Page<Person> page(String name, Pageable pageable) {
        return personRepository.findAllByNameContains(name, pageable);
    }
   @Test
	void test3() {
		List<Person> list = new ArrayList<>();
		String name = "test";
		for (int i = 0; i < 10; i++) {
			Person person = new Person();
			person.setName(name);
			list.add(person);
		}
		personService.saveAll(list);

		Page<Person> page = personService.page("es", PageRequest.of(0, 5));
		System.out.println("getTotalElements == "+page.getTotalElements());
		System.out.println("getSize == "+page.getSize());
		List<Person> content = page.getContent();
		for (Person person : content) {

			System.out.println("person == "+person);
		}

	}

执行结果
getTotalElements == 10
getSize == 5
person == Person{id=‘60cf1a815244aa1ac87dcbcc’, name=‘test’, age=null}
person == Person{id=‘60cf1a815244aa1ac87dcbcd’, name=‘test’, age=null}
person == Person{id=‘60cf1a815244aa1ac87dcbce’, name=‘test’, age=null}
person == Person{id=‘60cf1a815244aa1ac87dcbcf’, name=‘test’, age=null}
person == Person{id=‘60cf1a815244aa1ac87dcbd0’, name=‘test’, age=null}

关联表

@DBRef  注解关联
新加 entity
@Document
public class Classt {

    @Id
    private String id;
    private String name;


    public Classt(String name) {
        this.name = name;
    }

    public String getId() {
        return id;
    }
    public String getName() {
        return name;
    }

    @Override
    public String toString() {
        return "Classt{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}
public interface ClasstRepository  extends PagingAndSortingRepository<Classt,String> {
}

    @Override
    public Person save(Person person, List<Classt> classts) {
        person.setClasstes(classts);
        return personRepository.save(person);
    }

    @Override
    public void saveAll(List<Person> persons) {
        personRepository.saveAll(persons);
    }

    @Override
    public Page<Person> page(String name, Pageable pageable) {
        return personRepository.findAllByNameContains(name, pageable);
    }

    @Override
    public Classt saveClasst(String name) {
        Classt classt = new Classt(name);
        return classtRepository.save(classt);
    }
	@Test
	void test4() {
		Classt classt = personService.saveClasst("一班");
		Person save = personService.save("test4");
		System.out.println("save == " + save);
		List<Classt> classts = new ArrayList<>();
		classts.add(classt);
		save.setClasstes(classts);
		personService.save(save, classts);

		//读取
		Person result = personService.findById(save.getId());
		System.out.println("result == " + result);

	}

结果
result == Person{id=‘60cf2e22a53a115ac3a96de7’, name=‘test4’, age=null, classtes=[Classt{id=‘60cf2e22a53a115ac3a96de6’, name=‘一班’}]}
如果没有@DBRef
在这里插入图片描述
classt就不会生成

GridFs

@Autowired
    private GridFsTemplate gridFsTemplate;

保存和提取

 @Override
    public void storeFileToGridFs(String path) throws FileNotFoundException {
        File file = new File(path);
        FileInputStream fis = new FileInputStream(file);
        gridFsTemplate.store(fis, "filename.txt");
    }
     @Override
    public void findFilesInGridFs(String fileName) throws IOException {
        GridFsResource resource = gridFsTemplate.getResource("filename.txt");
        InputStream stream = resource.getInputStream();
        byte[] bytes = StreamUtils.copyToByteArray(stream);
        Path path = Paths.get("E:\\", fileName);
        Files.write(path, bytes);
    }

	@Test
	void test8() throws IOException {
		personService.findFilesInGridFs("602.JPG");
	}

在这里插入图片描述

Querydsl

添加依赖
       		<dependency>
			<groupId>com.querydsl</groupId>
			<artifactId>querydsl-apt</artifactId>
			<version>${querydsl.version}</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>com.querydsl</groupId>
			<artifactId>querydsl-mongodb</artifactId>
			<version>${querydsl.version}</version>
		</dependency>
		<dependency>
			<groupId>org.mongodb.morphia</groupId>
			<artifactId>morphia</artifactId>
			<version>1.3.2</version>
		</dependency>

在添加plugin

			<plugin>
				<groupId>com.mysema.maven</groupId>
				<artifactId>apt-maven-plugin</artifactId>
				<version>1.1.3</version>
				<executions>
					<execution>
						<goals>
							<goal>process</goal>
						</goals>
						<configuration>
							<outputDirectory>target/generated-sources/java</outputDirectory>
							<processor><processor>com.querydsl.apt.morphia.MorphiaAnnotationProcessor</processor>
						</configuration>
					</execution>
				</executions>
			</plugin>
idea 的话 双击ctrl ,执行 mvn clean package  -Dmaven.test.skip=true   
结果target/generated-sources/java发现没有生成文件,在实体上添加@Entity,即可
点开com.querydsl.apt.morphia.MorphiaAnnotationProcessor

@SupportedAnnotationTypes({“com.querydsl.core.annotations.","org.mongodb.morphia.annotations.”})
这个是 支持的注解
将之前的PersonRepository进行修改

public interface PersonRepository extends MongoRepository<Person, String>, QuerydslPredicateExecutor<Person> {
    Optional<Person> findFirstByName(String name);

    Page<Person> findAllByNameContains(String name, Pageable pageable);
}

这里是多添加了继承QuerydslPredicateExecutor,
然后service 添加接口

private QPerson qPerson = QPerson.person;


@Override
    public List<Person> findAllQueryDsl(String name, Integer age) {
        BooleanExpression expression = qPerson.name.contains(name)
                .or(qPerson.age.goe(age));
        return Lists.newArrayList(personRepository.findAll(expression));
    }

添加测试用例

	@Test
	void test9() throws IOException {
		createBatch();
		List<Person> content = personService.findAllQueryDsl("te", 5);
		for (Person person : content) {
			System.out.println("person == "+person);
		}
	}

person == Person{id=‘6129e8eeb809463b2ee1c1fc’, name=‘test’, age=26, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c1fd’, name=‘test’, age=19, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c1fe’, name=‘test’, age=18, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c1ff’, name=‘test’, age=40, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c200’, name=‘test’, age=46, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c201’, name=‘test’, age=30, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c202’, name=‘test’, age=4, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c203’, name=‘test’, age=26, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c204’, name=‘test’, age=15, classtes=null}
person == Person{id=‘6129e8eeb809463b2ee1c205’, name=‘test’, age=26, classtes=null}

对于短时间开发,又对mongodb 的语法不了解,又有使用DSL 来说,是很方便的,基本不用去了解具体的查询构造

mongoTemplate

随着业务对接的表越来越多,Jpa 一个Collections 至少要新建 一个 Entity, 一个Repository,而 dsl 也是如此,就显的很麻烦,这时候就可以使用mongoTemplate
其中mongoTemplate 的find 有两种实现
第一种:

<T> List<T> find(Query query, Class<T> entityClass);

参数是查询语句和类,其中对应的Collections 名字可以类上添加@Document(“t_person”) 来实现

第二种

<T> List<T> find(Query query, Class<T> entityClass, String collectionName);

参数查询语句和类,其中对应的Collections 名字由 collectionName 传入,class 的@Document(“t_person”) 无效

添加代码

    @Autowired
    private MongoTemplate mongoTemplate;

   @Override
    public List<Person> findAllByTemplate(String name, Integer age) {
        List<Person> people = mongoTemplate.find(Query.query(Criteria.where("name").is(name).and("age").gt(age)),
                Person.class);
        return people;
    }
   @Test
	void test11() throws IOException {
		createBatch();
		List<Person> content = personService.findAllByTemplate("test", 15);
		for (Person person : content) {
			System.out.println("person == "+person);
		}
	}

person == Person{id=‘6129ef1543275b55d42a533b’, name=‘test’, age=45, classtes=null}
person == Person{id=‘6129ef1543275b55d42a533c’, name=‘test’, age=44, classtes=null}
person == Person{id=‘6129ef1543275b55d42a533f’, name=‘test’, age=24, classtes=null}
person == Person{id=‘6129ef1543275b55d42a5340’, name=‘test’, age=18, classtes=null}
person == Person{id=‘6129ef1543275b55d42a5342’, name=‘test’, age=46, classtes=null}

如果要完全等于findAllQueryDsl 的话

 @Override
    public List<Person> findAllByTemplate(String name, Integer age) {
        List<Person> people = mongoTemplate.find(Query.query(Criteria.where("name").regex(".*\\Qte\\E.*").and("age").gte(age)),
                Person.class);
        return people;
    }

会麻烦一些

但是也有些好处,比如不用在写Repository,如果多个表的字段类似,可以写通用的Query
或者将Entity也忽略掉
如下

 @Override
    public void saveMap(String str) throws IOException {
        Map<String, String> map = new HashMap<>();
        map.put("_id", str);
        map.put("id", str);
        mongoTemplate.save(map, "wjm");
    }
  @Override
    public List<Map> getMap(String str) throws IOException {
        Query query = Query.query(Criteria.where("_id").is(str));
        return mongoTemplate.find(query, Map.class, "wjm");
    }

不过其中"_id" 要做唯一主键

@Test
	void test10() throws IOException {
		personService.saveMap("date");
		List<Map> map = personService.getMap("date");
		for (Map m : map) {
			System.out.println(" == "+m);
		}
	}

== {_id=date, id=date}
还是蛮有意思

源码地址

github

来源

starters
jpa
Mapping Annotation Overview
事务
examples

作者博客

dzl

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值