Laravel 自动转换长整型雪花 ID 为字符串的实现

在设计 API 时,出于安全性等因素考虑,有时需要放弃使用自增 ID,使 ID 非连续且不可猜测。通常可以使用 Hash id,UUID,雪花 ID 等来实现。

在最近的一个项目中,我尝试使用雪花 ID。一通折腾下来发现,逼格挺高,实现也挺简单。然而当我继续撸起袖子与前端部分对接时,却出现了 JS 精度丢失问题,因为存储的 ID 是一个 unsigned bigint 型的值。(至于为什么会有精度丢失现象,这里就不具体解释了,不清楚的可以自行搜索),本文主要介绍解决办法。

想要解决这问题,基本原理也很简单,就是把 ID 转成字符串再返回给前端。

错误尝试

一开始我想到的是使用 Laravel Eloquent 模型的模型访问器。只要给需要转换的模型加一个 getIdAttribute,将 ID 转成字符串不就行了嘛?

如:AppModelsUser 模型里这样写:

/**
 * @return string
 */
public function getIdAttribute()
{
  return strval($this->attributes['id']);
}

但事实并非如此,属性访问器确实能让 API 返回给前端的 ID 变为字符串。但同时也会影响关联模型插入、修改时的结果,例如,user 关联的了 post 模型,使用 $user->posts()->saveMany(...); 这种方式保存的新的 posts 记录,对应的 user_id 会为空。

这也不难理解,因为模型访问器是要参与模型相关处理的,访问器将 ID 由数字转为了字符串,自然会导致数据错乱。

正确姿势

冷静下来决定先认真思考再动手,查阅了官方文档,才发现 Resource 正是我想要的。Resource 只会影响返回给前端的数据,我们可以通过自定义 Resource 来实现 API 返回结果的结构、类型转换等功能。转换个 ID 自然也不在话下。

为了省事,我直接修改 AppHttpResource 这个基类。只需要重载它的 toArray() 方法,在其中使用递归,对可能超出 JS 安全数值范围的值进行转换就可以了。大家也可以根据自己的实际情况,新建 Resource 类,如 UserResource 来处理。

<?php

namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class Resource extends JsonResource
{
  /**
   * Transform the resource into an array.
   *
   * @param \Illuminate\Http\Request $request
   *
   * @return array
   */
  public function toArray($request)
  {
    $parentReturn = parent::toArray($request);

    foreach (array_keys($parentReturn) as $key) {
      // 为方便演示这里把所有整型字段都转成字符串
      if (is_int($parentReturn[$key])) {
        $parentReturn[$key] = strval($parentReturn[$key]);
      }

      // 关联的字段,如 $user->post,相当于递归处理
      if (is_array($parentReturn[$key])) {
        $parentReturn[$key] = new Resource($parentReturn[$key]);
      }
    }

    return $parentReturn;
  }
}

然后,在接口控制器中返回 Resource 返回数据,整型字段值就会自动变为字符串了。

<?php

namespace App\Http\Controllers;

use App\Http\Resources\Resource;
use App\Models\User;
use Illuminate\Http\Request;

class TestController extends Controller
{
  /**
   * @return \App\Http\Resources\Resource
   */
  public function __invoke(Request $request)
  {
    $user = User::first();

    return new Resource($user);
  }
}

结果如下图:

注意事项

因为这种办法使用了遍历,而且有递归处理,当数据结构复杂、数据量较大时可能会对性能造成一定影响。我这里算是比较偷懒取巧的写法,如果对性能有追求,自定义 Resource 类,然后根据特定的已知的字段名来进行转换会比较好
因为返回给前端的 ID 转为了字符串,前端在进行比较判断,特别是 === 判断时要特别注意

到此这篇关于Laravel 自动转换长整型雪花 ID 为字符串的实现的文章就介绍到这了,更多相关Laravel 长整型雪花ID转换为字符串内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Laravel项目中timeAgo字段语言转换的改善方法示例

    前言 在我们过去的Laravel项目中,经常需要用到time_ago这样的字段,并将其转换为我们熟悉的本地语言,可以实现的方式有很多,比如编写一个time_ago的辅助函数将其转换成本地,或采用carbon的diffForHumans函数然后替换成本地语言来实现. 过去我们编写过的代码像这样: 这样 但是我们需要将其替换成中文.繁体中文.日本或是韩文时,我们就需要编写多个类似的方法如: time_ago_CN //简体中文 time_ago_HK //繁体中文 time_ago_JP //日文

  • laravel5.6实现数值转换

    在laravel框架中,如果希望从数据库中取出的值就是我们希望的类型,可以使用laravel框架模型中的$casts属性值来将需要的字段转换成需要的类型,用法如下: <?php namespace App; use Illuminate\Database\Eloquent\Model; class User extends Model { /** * 应该被转化为原生类型的属性 * * @var array */ protected $casts = [ //字段=>希望转换的类型 'is_a

  • laravel 字段格式化 modle 字段类型转换方法

    有些字段会用base64_decode加密存储,在每次查询都要查询出来解码.比较麻烦,laravel的model提供方法处理 在对应的model里面 格式为(set/get)(字段名称,注1)(Attribute) 注: 1.首字母大写,下划线的地方字母大写.例如product_json在这里的写法是ProductJson /** * 查询用户的时候name字段处理 * * @author Eric * @param $value * @return string */ public funct

  • 在laravel中实现将查询的对象转换为多维数组的函数

    我们在laravel中通过数据库查询,有时获取的为对象.但是在进行使用excel类的时候,要求我们使用的多维数组.那么我们就不要进行转换了,如果使用toArray()无能将对象转换我们想要的类型,就需要手动转换. 下面贴代码: //函数处理,转换为表格需求的格式 $d =[]; foreach ($goods as $k=>$v) { $m = []; foreach ($v as $i=>$j) { $m[$i] = $j; } $d[$k] = $m; } 备注$goods是数组查询出来的

  • Laravel 自动转换长整型雪花 ID 为字符串的实现

    在设计 API 时,出于安全性等因素考虑,有时需要放弃使用自增 ID,使 ID 非连续且不可猜测.通常可以使用 Hash id,UUID,雪花 ID 等来实现. 在最近的一个项目中,我尝试使用雪花 ID.一通折腾下来发现,逼格挺高,实现也挺简单.然而当我继续撸起袖子与前端部分对接时,却出现了 JS 精度丢失问题,因为存储的 ID 是一个 unsigned bigint 型的值.(至于为什么会有精度丢失现象,这里就不具体解释了,不清楚的可以自行搜索),本文主要介绍解决办法. 想要解决这问题,基本原

  • JS长整型精度问题实例分析

    本文实例分析了一个JS长整型精度问题.分享给大家供大家参考.具体分析如下: 问题描述: 后台有一个脚本功能,可编写脚本动态调用Java代码 复制代码 代码如下: importClass(com.ztgame.center.controller.api,P360ApiController);  var roleId = 10214734953631045;  p360ApiController.notice(roleId, 4); 脚本执行成功,但运行结果与设定不一样,此人没有收到邮件 查看日志 

  • Python整型运算之布尔型、标准整型、长整型操作示例

    本文实例讲述了Python整型运算之布尔型.标准整型.长整型操作.分享给大家供大家参考,具体如下: #coding=utf8 def integerType(): ''''' 布尔型: 该值的取值范围只有两个值:True(1).False(0) ''' Tbool=True Fbool=False print "The True is stand for %d" %(Tbool) print "The False is stand for %d" %(Fbool)

  • 将IP地址转换为整型数字的PHP方法、Asp方法和MsSQL方法、MySQL方法

    首先我们要先了解一下IP地址转换为整型(严格来说应该说是长整型)的原理~ [转换原理]:假设IP为:w.x.y.z,则IP地址转为整型数字的计算公式为:intIP = 256*256*256*w + 256*256*x + 256*y + z [PHP的互转]:PHP的转换方式比较简单,它内置了两个函数int ip2long ( string $ip_address )和 string long2ip ( string $proper_address )可以直接调用使用~ [Asp的互转]:自定

  • 深入分析python中整型不会溢出问题

    本次分析基于 CPython 解释器,python3.x版本 在python2时代,整型有 int 类型和 long 长整型,长整型不存在溢出问题,即可以存放任意大小的整数.在python3后,统一使用了长整型.这也是吸引科研人员的一部分了,适合大数据运算,不会溢出,也不会有其他语言那样还分短整型,整型,长整型...因此python就降低其他行业的学习门槛了. 那么,不溢出的整型实现上是否可行呢? 不溢出的整型的可行性 尽管在 C 语言中,整型所表示的大小是有范围的,但是 python 代码是保

  • C语言的合法标识符与整型详解

    目录 头文件 常量 变量 命名规范 合法的浮点数 小数与指数 char与八进制 以下通过代码来举例 sizeof() 数据溢出 整型 面向过程 流程 入口.出口 注释 进制转换 总结 首先我们来介绍一下,一开始学习c语言最先遇到的头文件是什么 头文件 又名工具箱 提供一系列方法(工具) #include <stdio.h> #include "stdio.h" <>: 直接在系统目录进行查找 找不到会直接报错 " ": 先在当前目录下进行查找

  • java并发JUC工具包AtomicInteger原子整型语法基础

    目录 1.AtomicInteger基础用法 2.什么时候需要使用AtomicInteger 2.1.原子计数器场景 2.2.数值比对及交换操作 3.总结 AtomicInteger 类底层存储一个int值,并提供方法对该int值进行原子操作.AtomicInteger 作为java.util.concurrent.atomic包的一部分,从Java 1.5开始引入. 1. AtomicInteger基础用法 通过下文的AtomicInteger构造方法,可以创建一个AtomicInteger对

  • 浅谈MySql整型索引和字符串索引失效或隐式转换问题

    目录 问题概述 问题重现 问题引申 结论 问题概述 今天在上班时,DBA突然找出来一段sql,表示该sql存在隐式转换,不走索引.经过我们的查看后,发现是类型varchar的字段, 我们使用条件传入了数值型的值,由于担心违反保密协议,在此就不贴图了,由我重现一下类似情况给大家看一下. 问题重现 首先我们先创建一张用户表test_user,其中USER_ID为了效果我们设置为varchar类型且加上唯一索引. CREATE TABLE test_user ( ID int(11) NOT NULL

  • 如何通过配置自动实现ValueList中hql语句的整型参数转换

    通过valuelist的queryMap传递过来的参数默认都为string类型,在valuelist配置文件的hql中,如果直接将该值赋给整型的字段会报错.一般我们会在hql中利用转型函数来进行处理,如下: 复制代码 代码如下: <entry key="areasInfoAdapter">       <bean  parent="abstractHibernate30Adapter">                   <prope

  • C++中字符串与整型及浮点型转换全攻略

    目录 一.string 和 char [] 1. string 转 char [] 2. char [] 转 string 二.char [] 与数字互转 1. char [] 转整型和浮点型 2. 整型和浮点型 转char [] 3. 整型转 char [] (特殊函数实现) 首先请出今日主角:stdlib.h (YYDS) 这个库包含有随机数,abs等许多通用函数,当然也有类型的转换 下面我们一点点来看如何完成格式转换 一.string 和 char [] 1. string 转 char

随机推荐