对用户IP归属地实现优雅的异步处理

72 阅读2分钟

1.基本类的创建以及相关配置

原理:通过ip访问开放api,获取返回json数据

String body = HttpUtil.get("https://ip.taobao.com/outGetIpInfo?ip=" + ip + "&accessKey=alibaba-inc");

对body进行反序列化

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IpDetail implements Serializable {

    private static final long serialVersionUID = 1L;
    //注册时的ip
    private String ip;
    //最新登录的ip
    private String isp;
    private String isp_id;
    private String city;
    private String city_id;
    private String country;
    private String country_id;
    private String region;
    private String region_id;
}
@Data
public class IpInfo implements Serializable {

    private static final long serialVersionUID = 1L;
    //注册时的ip
    private String createIp;
    //注册时的ip详情
    private IpDetail createIpDetail;
    //最新登录的ip
    private String updateIp;
    //最新登录的ip详情
    private IpDetail updateIpDetail;
}

对应映射对象 1.添加@TableName(value ="sec_user", autoResultMap = true),否则对象不能反序列化,结果为空 2.typeHandler = JacksonTypeHandler.class指定序列化工具类 3.mysql数据库中的数据结构为json

@TableName(value ="sec_user", autoResultMap = true)
@Data
public class User implements Serializable {
    /**
     * 主键
     */
    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    /**
     * 用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 
     */
    private String icon;

    /**
     * 昵称
     */
    private String nickname;

    /**
     * 电话
     */
    private Long phone;

    /**
     * 邮箱
     */
    private String mail;

    /**
     * 
     */
    private Integer state;

    /**
     * 
     */
    private Date updateTime;

    /**
     * 
     */
    private Date createTime;

    /**
     * 
     */
    @TableField( value = "ip_info",typeHandler = JacksonTypeHandler.class)

    private IpInfo ipInfo;

    @TableField(exist = false)
    private static final long serialVersionUID = 1L;
}

2.流程介绍

1.创建用户并添加数据库(只需要更新ip,不需要detail更新)

2.把用户的基本信息作为事件传递

3.使用uid更新detail

3.代码中实现

1.事件发布可以通过spring有关event的组件,将String换成User就行

/**
 * moudle------
 * <p></p>
 *
 * @author : zlx
 * @date : 2024-08-14 23:54
 **/
@Component
@Slf4j
public class Listener {
    @Async()
    @EventListener(classes = MyEvent.class)
    public void onEvent(MyEvent event)
    {
        String msg = event.getMsg();

log.info(msg);
    }
    @Async()
    @EventListener(classes = MyEvent.class)
    public void onEvent2(MyEvent event)
    {
        String msg = event.getMsg();

        log.info(msg+"demo1");

    }
}
@Getter
public class MyEvent extends ApplicationEvent {
    private final String msg;
    public MyEvent(Object source,String msg) {
        super(source);
        this.msg=msg;
    }
}

2.因为对象的嵌套关系User->ipInfo->IpDeatil 我们可以在外层对象中编写方法,创建或者修改内部对象的属性,减少new的使用

public void refreshIp(String ip) {
    if (ipInfo == null) {
        ipInfo = new IpInfo();
    }
    ipInfo.refreshIp(ip);
}

User对象中,设置一个基本的IpInfo

3.Ipinfo对象中,处理四个变量之间的关系和相互值设置

1.ip创建阶段:

1.创建时,设置updateIP和createIP 此时值是相同的,

2.当更新时,处理updateIP

public void CreatorRefreshIp(String ip) {
    if (StringUtils.isEmpty(ip)) {
        return;
    }
    updateIp = ip;
    if (createIp == null) {
        createIp = ip;
    }
}
2.detail处理阶段:

detail的第一步通过ip获取detail,有两种情景需要访问,获取需要处理的ip

情景1 detail为空

情景2 updateIp先行更新,detail不匹配

public String needRefreshIp() {
    //或条件的编写

    boolean notNeedRefresh = Optional.ofNullable(updateIpDetail)
            // 1
            .map(IpDetail::getIp)
            // 2.
            .filter(ip -> Objects.equals(ip, updateIp))
            .isPresent();
    return notNeedRefresh ? null : updateIp;
}

代码解释:.ofNullable(updateIpDetail)可返回空, .filter(ip -> Objects.equals(ip, updateIp))可返回空,两个条件是"或"关系

通过空判断bool

3.detail设置阶段

创建时,ip相同 两个detail都能实现 更新时,只更新 update的Detail

public void refreshIpDetail(IpDetail ipDetail) {


    if (Objects.equals(createIp, ipDetail.getIp())) {
        createIpDetail = ipDetail;
    }
    if (Objects.equals(updateIp, ipDetail.getIp())) {
        updateIpDetail = ipDetail;
    }
}

4工具类的封装

此笔记为mallchat的学习记录

参考少年阿斌/MallChat - 码云 - 开源中国 (gitee.com)中mallchat-chat-server/src/main/java/com/abin/mallchat/common/user/service/impl中的方法