2021SC@SDUSC
本篇文章围绕UserOpenidService、UserTagService两个接口以及实现类进行代码分析,主要内容为JPress对于第三方的访问的使用的信息记录,以及用户增加用户标签的非主要功能方法的实现。
文章目录
一、UserOpenidService
JPress搭建网站支持用户的第三方访问,如wechat、qq、钉钉、微博、github、gitee等,由此产生UserOpenidService与UserOpenidServiceProvider。
1.1 数据库表
因为JPress构建网站后,支持第三方的访问,因此需要给每个用户的每个第三方适配id。因此使用user_openid表。
1.2 UserOpenidService接口用途
因为对于该类的使用之处多在于用户登录、用户注销以及发布文章时的身份标识,因此接口多为增删改查的用途。
List<UserOpenid> findListByColumns(Columns columns);
根据某个列值(属性)查询数据,返回UserOpenid
类的对象。
boolean batchDeleteByIds(Object... ids);
根据多个id批量删除user_openid数据
Page<UserOpenid> paginate(int page, int pageSize);
使用分页技术对查询的用户第三方进行分页,适用于超级管理员批量查询用户时使用。
User findByTypeAndOpenId(String type, String openId);
根据第三方id以及第三方的类型查询出对应的用户账号
void batchDeleteByUserId(Object userId);
批处理删除用户id相关的第三方信息,用于删除该用户时同时对多个第三方的注销。
1.3 UserOpenidServiceProvider
UserOpenidServiceProvider提供对接口的方法实现。重要方法的解析如下:
@Override
@Cacheable(name = "useropenid",key = "#(type)-#(openId)")
public User findByTypeAndOpenId(String type, String openId) {
if (StrUtil.isBlank(type) || StrUtil.isBlank(openId)){
return null;
}
UserOpenid userOpenid = DAO.findFirstByColumns(Columns.create("type", type).eq("value", openId));
return userOpenid != null ? userService.findById(userOpenid.getUserId()) : null;
}
- findByTypeAndOpenId方法为通过第三方的类型与对应的第三方openid进行用户的查找,返回user对象。
- 使用@Cacheable注解,将查询的结果存储在缓存当中,key为(type)-(openId)的形式,name为useropenid。
- 使用底层的DAO层首先查找userOpenid ,其中使用了
io.jboot.db.model.Columns;
的属性操作的create与eq方法。如果查询成功,通过userOpenid 查询表中该openid对应的user对象。
@Override
public void shouldUpdateCache(int action, Model model, Object id) {
if (model instanceof UserOpenid){
UserOpenid userOpenid = (UserOpenid) model;
Jboot.getCache().remove("useropenid",userOpenid.getType()+"-"+userOpenid.getValue());
}
}
- shouldUpdateCache方法意为将状态设置为应该更新缓存,待自动更新缓存时会将对应内容更新。
- 如果model(代表一行数据或一个对象)是UserOpenid类的实例对象,则将model转换为UserOpenid类。
- 通过Jboot的getCache的方法读取缓存,并将对应key的缓存值删除,以利于下次更新缓存。
二、UserTagService
本类的接口与实现类实现了用户对自己的tag的增加和删除,有利于在使用SEO关键字时搜索到对应的用户。
2.1 数据库表
首先需要一个记录tag的数据库表。
有了tag以及id之后,因为每个用户有多个tag,所以需要一张tag与user的映射表。
2.2 UserTagService接口用途
撇开对tag的简单增删改查的接口不谈,UserTagService中还有部分重要接口函数。
Page<UserTag> paginateByColumns(int page, int pageSize, Columns columns, String orderBy);
对固定的columns进行排序,返回Page对象
List<UserTag> findListByUserId(Object userId);
通过用户的id找到他本人所有的用户tag,返回tag的列表。
List<UserTag> findHotList(int count);
通过计数,找到热度最高的tag的列表。
void doUpdateTags(long userId, Long[] tagIds);
输入一串tag的id,更新用户的tag。
2.3 UserTagServiceProvider
UserOpenidServiceProvider提供对接口的方法实现。重要方法的解析如下:
@Override
public List<UserTag> findListByUserId(Object userId) {
List<Record> mapping = Db.find("select * from user_tag_mapping where user_id = ?",userId);
if (mapping == null || mapping.isEmpty()){
return null;
}
return mapping.stream()
.map(record -> findById(record.get("tag_id")))
.collect(Collectors.toList());
}
- findListByUserId方法的目的为通过用户的id找到他本人所有的用户tag,返回tag的列表。
- 通过Db查询到user_tag_mapping中对应该用户的所有tagid。
- 使用stream()方法获得集合操作的数据流,并在user_tag表中用map()方法得到了对应的tag值。
注:stream()的使用
- Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作。使用Stream API 对集合数据进行操作,就类似于使用 SQL 执行的数据库查询。也可以使用 Stream API 来并行执行操作。简而言之,Stream API 提供了一种高效且易于使用的处理数据的方式。
- 特点:
- 不是数据结构,不会保存数据。
- 不会修改原来的数据源,它会将操作后的数据保存到另外一个对象中。(保留意见:毕竟peek方法可以修改流中元素)
- 惰性求值,流在中间处理过程中,只是对操作进行了记录,并不会立即执行,需要等到执行终止操作的时候才会进行实际的计算。
@Override
public void doUpdateTags(long userId, Long[] tagIds) {
Db.tx(() -> {
Db.update("delete from user_tag_mapping where user_id = ?", userId);
if (tagIds != null && tagIds.length > 0) {
List<Record> records = new ArrayList<>();
for (long tagId : tagIds) {
Record record = new Record();
record.set("user_id", userId);
record.set("tag_id", tagId);
records.add(record);
}
Db.batchSave("user_tag_mapping", records, records.size());
}
return true;
});
}
- doUpdateTags方法的作用是根据输入的一组tagId的值更新tag。
- 实现通过Db操作,删除用户与tag表之间的映射的信息。
- 在通过传入的tagId数组,重新生成Record 信息,添加入user_tag_mapping表中,实现了读目前tag的映射的更新。