写在前面

本文将在第六篇《使用ElasticSearch实现商品复杂搜索》的基础上整合MongoDB,实现用户商品浏览记录这一功能。

MongoDB

MongoDB简介

MongoDB是一个为快速开发互联网Web应用而构建的数据库系统,其数据模型和持久化策略就是为了构建高读/写吞吐量和高自动灾备伸缩性的系统。

安装MongoDB服务

第一步,点击 这里 下载MongoDB的安装包;

第二步,自定义MongoDB的安装路径:

第三步,在MongoDB安装路径下创建data\dbdata\log这两个文件夹:

第四步,在MongoDB安装路径下创建mongod.cfg配置文件,里面的配置信息如下:

1
2
3
4
5
systemLog:
destination: file
path: E:\Application\MongoDB\data\log\mongod.log
storage:
dbPath: E:\Application\MongoDB\data\db

第五步,进入到MongoDB安装路径下的bin目录,里面有两个exe文件,分别是客户端和服务端运行程序:

然后以管理员身份打开终端,并切换到bin目录下,执行如下命令来给系统安装MongoDB服务:

1
E:\Application\MongoDB\bin\mongod.exe --config "E:\Application\MongoDB\mongod.cfg" --install

第六步,一些与MongoDB服务管理相关的命令:

1
2
3
启动服务:net start MongoDB
关闭服务:net stop MongoDB
移除服务:E:\Application\MongoDB\bin\mongod.exe --remove

使用上述命令来启动MongoDB服务。

安装MongoDB客户端

第一步,点击 这里 下载MongoDB客户端的安装包;

第二步,将其解压到指定目录,并打开名为robo3t.exe的软件,然后连接到localhost:27017

Spring Data MongoDB

Spring Data MongoDB是Spring提供的一种以Spring Data风格来操作数据存储的方式,可以避免开发者编写大量的样板代码,提升代码质量。

Spring Data MongoDB常用注解

@Document

@Document注解添加到需要映射到MongoDB文档上的领域对象上:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface Document {
@AliasFor("collection")
String value() default "";

@AliasFor("value")
String collection() default "";

String language() default "";
}

@Id

@Id注解添加到映射到MongoDB文档上的领域对象的ID字段上,即文档的id,类似于数据库中的行:

1
2
3
4
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
public @interface Id {
}

@Indexed

@Indexed注解添加到映射到MongoDB文档上的领域对象的某个字段上,用于标识该字段为MongoDB的索引字段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Target({ElementType.ANNOTATION_TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Indexed {
boolean unique() default false;

IndexDirection direction() default IndexDirection.ASCENDING;

boolean sparse() default false;

/** @deprecated */
@Deprecated
boolean dropDups() default false;

String name() default "";

boolean useGeneratedName() default false;

boolean background() default false;

int expireAfterSeconds() default -1;
}

Spring Data操作数据的方式

如果你之前使用过JPA,你会发现Spring Data操作数据的方式都是类似的,即继承XXXRepository接口,然后就可以获得一些操作数据的常用方法。此处是继承MongoRepository接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@NoRepositoryBean
public interface MongoRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
<S extends T> List<S> saveAll(Iterable<S> var1);

List<T> findAll();

List<T> findAll(Sort var1);

<S extends T> S insert(S var1);

<S extends T> List<S> insert(Iterable<S> var1);

<S extends T> List<S> findAll(Example<S> var1);

<S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

实际上开发者也可以使用衍生查询,即在接口中直接指定查询方法的名称就可以实现查询,无需提供具体的实现:

就像后面会使用到的,根据会员id按照时间倒序获取会员的浏览记录,直接在接口中定义如下方法即可:

1
2
3
4
5
6
7
8
9
10
11
/**
* 会员商品浏览历史记录Repository
*/
public interface MemberReadHistoryRepository extends MongoRepository<MemberReadHistory,String> {
/**
* 根据会员id按照时间倒序获取商品浏览历史记录
* @param memberId 会员id
* @return 商品浏览历史记录
*/
List<MemberReadHistory> findByMemberIdOrderByCreateTimeDesc(Long memberId);
}

如果开发者使用的IDE是IDEA,那么它会在开发者编写方法的时候直接提示对应字段信息:

当然了,开发者也可以使用@Query注解,直接使用MongoDB的JSON语句来进行查询:

1
2
@Query("{ 'memberId' : ?0 }")
List<MemberReadHistory> findByMemberId(Long memberId);

整合MongoDB实现用户商品浏览记录

第一步,复制一份shop-elasticsearch源码,将其名字修改为shop-mongodb,然后对应包和文件中的信息也记得修改,本篇后续所有操作均在shop-mongodb这一Module中进行。注意复制之后需要重新执行一下Generator类,以覆盖之前项目的自动生成文件。关于如何使用IDEA复制module,可以点击 这里 进行阅读。

第二步,在shop-mongodb的POM文件中新增如下依赖:

1
2
3
4
5
<!---MongoDB相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

第三步,往application.yml配置文件中在spring.data节点下添加MongoDB相关配置信息:

1
2
3
4
5
6
# MongoDB相关
data:
mongodb:
host: localhost # mongodb的连接地址
port: 27017 # mongodb的连接端口号
database: shop-port # mongodb的连接的数据库

第四步,在nosql包内定义一个名为mongodb的包,接着在mongodb包内定义一个名为document的包。然后在document包内定义一个名为MemberReadHistory的类,注意这是会员浏览记录文档对象。然后文档对象的ID域使用@Id注解,需要检索的字段添加@Indexed注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 用户商品浏览历史记录文档对象
*/
@Data
@Document
public class MemberReadHistory {
@Id
private String id;
/**
* 用户id
*/
@Indexed
private Long memberId;
/**
* 用户昵称
*/
private String memberNickname;
/**
* 用户头像
*/
private String memberIcon;
/**
* 商品id
*/
@Indexed
private Long productId;
/**
* 商品名称
*/
private String productName;
/**
* 商品图片
*/
private String productPic;
/**
* 商品副标题
*/
private String productSubTitle;
/**
* 商品价格
*/
private String productPrice;
/**
* 浏览时间
*/
private Date createTime;
}

第五步
在mongodb包内新建一个名为repository的包,并在该包内定义一个名为MemberReadHistoryRepository的接口,注意这个接口需要继承MongoRepository接口,这样就拥有了一些基本的操作MongoDB数据的方法,同时我们在里面定义了一个衍生的根据用户(会员)id按照时间倒序获取商品浏览历史记录的方法:

1
2
3
4
5
6
7
8
9
10
11
/**
* 会员商品浏览历史记录Repository
*/
public interface MemberReadHistoryRepository extends MongoRepository<MemberReadHistory,String> {
/**
* 根据会员id按照时间倒序获取商品浏览历史记录
* @param memberId 会员id
* @return 商品浏览历史记录
*/
List<MemberReadHistory> findByMemberIdOrderByCreateTimeDesc(Long memberId);
}

第六步,在service包内定义一个名为MemberReadHistoryService的接口,用于定义与会员浏览商品历史记录管理相关的接口方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 会员浏览商品历史记录管理 Service
*/
public interface MemberReadHistoryService {
/**
* 生成浏览历史记录
* @param memberReadHistory 浏览历史记录信息
*/
int create(MemberReadHistory memberReadHistory);

/**
* 批量删除浏览历史记录
* @param ids 浏览历史记录id
*/
int delete(List<String> ids);

/**
* 获取指定会员的浏览历史记录
* @param memberId 会员id
*/
List<MemberReadHistory> list(Long memberId);
}

第七步,在impl包内定义一个名为MemberReadHistoryServiceImpl的类,这个类需要实现MemberReadHistoryService接口,并重写其中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
* 会员浏览商品历史记录管理Service的实现类
*/
@Service
public class MemberReadHistoryServiceImpl implements MemberReadHistoryService {
@Autowired
private MemberReadHistoryRepository memberReadHistoryRepository;

@Override
public int create(MemberReadHistory memberReadHistory) {
memberReadHistory.setId(null);
memberReadHistory.setCreateTime(new Date());
memberReadHistoryRepository.save(memberReadHistory);
return 1;
}

@Override
public int delete(List<String> ids) {
List<MemberReadHistory> deleteMemberReadHistoryLists = new ArrayList<>();
for(String id:ids){
MemberReadHistory memberReadHistory = new MemberReadHistory();
memberReadHistory.setId(id);
deleteMemberReadHistoryLists.add(memberReadHistory);
}
memberReadHistoryRepository.deleteAll(deleteMemberReadHistoryLists);
return deleteMemberReadHistoryLists.size();
}

@Override
public List<MemberReadHistory> list(Long memberId) {
return memberReadHistoryRepository.findByMemberIdOrderByCreateTimeDesc(memberId);
}
}

第八步,在controller包内定义一个名为MemberReadHistoryController的类,这是会员商品浏览历史记录管理的Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/**
* 会员商品浏览历史记录管理Controller
*/
@Api(tags = "MemberReadHistoryController",description = "会员商品浏览历史记录管理")
@RestController
@RequestMapping("/member/readHistory")
public class MemberReadHistoryController {
@Autowired
private MemberReadHistoryService memberReadHistoryService;

@ApiOperation("创建浏览记录")
@PostMapping( "/create")
public CommonResult create(@RequestBody MemberReadHistory memberReadHistory) {
int count = memberReadHistoryService.create(memberReadHistory);
if (count > 0) {
return CommonResult.success(count);
} else {
return CommonResult.failed();
}
}

@ApiOperation("删除浏览记录")
@PostMapping("/delete")
public CommonResult delete(@RequestParam("ids") List<String> ids) {
int count = memberReadHistoryService.delete(ids);
if (count > 0) {
return CommonResult.success(count);
} else {
return CommonResult.failed();
}
}

@ApiOperation("展示浏览记录")
@GetMapping("/list")
public CommonResult<List<MemberReadHistory>> list(@RequestParam(value = "memberId")@ApiParam("会员id") Long memberId) {
List<MemberReadHistory> memberReadHistoryList = memberReadHistoryService.list(memberId);
return CommonResult.success(memberReadHistoryList);
}
}

第九步,启动项目,访问Swagger-UI接口文档地址,即浏览器访问http://localhost:8080/swagger-ui.html链接,可以看到新的接口已经出现了:

第十步,进行接口测试。首先后台用户进行登录,接着测试“创建浏览记录”:

可以更改memberId来创建两条测试数据:

接着测试一下查看某会员商品浏览历史记录接口:

这样本篇关于整合MongoDB实现用户商品浏览记录的学习就完成了,后续介绍如何整合RabbitMQ实现延迟消息这一功能。本篇笔记源码,可以点击 这里 进行阅读。