You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel/MySQL如何强制返回5位小数(无需逐个字段处理)

解决MySQL/Laravel返回double字段小数位数过多的问题

一、MySQL层面方案

1. 创建视图批量处理字段

要是不想在Laravel里写额外逻辑,可以在MySQL中创建视图,自动把所有double(20,5)类型的字段统一保留5位小数。
先查询表中所有double类型字段:

SELECT COLUMN_NAME 
FROM INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_SCHEMA = '你的数据库名' 
AND TABLE_NAME = 'invoices' 
AND DATA_TYPE = 'double';

接着用这些字段生成视图SQL,每个数值字段用ROUND(字段名,5) AS 字段名,非数值字段直接保留:

CREATE VIEW invoices_view AS
SELECT 
  id,
  entity_id,
  ROUND(net_total,5) AS net_total,
  ROUND(total_vat,5) AS total_vat,
  ROUND(grand_total,5) AS grand_total,
  -- 其他字段依次列出,非数值字段直接写字段名
FROM invoices;

之后把Laravel的Invoice模型$table属性改成invoices_view,查询时就会自动返回处理后的小数结果。

2. 动态生成SELECT语句(适合临时场景)

如果不想创建视图,也可以在Laravel里通过查询信息表获取所有double字段,动态生成带ROUND的查询语句:

// 获取表中所有double类型字段
$decimalColumns = DB::select("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND DATA_TYPE = 'double'", [config('database.connections.mysql.database'), 'invoices']);
$decimalColumnNames = collect($decimalColumns)->pluck('COLUMN_NAME')->toArray();

// 获取表中所有字段
$allColumns = DB::select("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?", [config('database.connections.mysql.database'), 'invoices']);

// 构造查询字段,数值字段加ROUND处理
$selectFields = [];
foreach ($allColumns as $col) {
    $field = $col->COLUMN_NAME;
    if (in_array($field, $decimalColumnNames)) {
        $selectFields[] = "ROUND({$field},5) AS {$field}";
    } else {
        $selectFields[] = $field;
    }
}

// 执行查询
$invoices = DB::table('invoices')->selectRaw(implode(', ', $selectFields))->get();

二、Laravel层面方案

1. 模型动态注册访问器

在Invoice模型中自动为所有double字段注册访问器,统一处理小数位数:

class Invoice extends Model
{
    protected static function booted()
    {
        // 获取表中所有double类型字段
        $columns = DB::select("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND DATA_TYPE = 'double'", [config('database.connections.mysql.database'), 'invoices']);
        
        foreach ($columns as $col) {
            $column = $col->COLUMN_NAME;
            // 注册模型检索后的处理逻辑
            static::retrieved(function ($model) use ($column) {
                if (isset($model->$column)) {
                    $model->$column = round($model->$column, 5);
                }
            });
        }
    }
}

这样每次模型查询到数据后,会自动处理所有double字段,保留5位小数。

2. 资源集合统一处理

创建资源类,在返回数据时统一处理所有浮点型字段:

// app/Http/Resources/InvoiceResource.php
namespace App\Http\Resources;

use Illuminate\Http\Resources\Json\JsonResource;

class InvoiceResource extends JsonResource
{
    public function toArray($request)
    {
        $data = parent::toArray($request);
        // 遍历字段,处理浮点数值
        foreach ($data as $key => $value) {
            if (is_numeric($value) && !is_int($value)) {
                $data[$key] = round($value, 5);
            }
        }
        return $data;
    }
}

// 控制器中返回集合
use App\Http\Resources\InvoiceCollection;

public function index()
{
    return new InvoiceCollection(Invoice::all());
}

这种方法不用关心具体字段,只要是浮点型数值都会自动保留5位小数。

3. 全局响应中间件处理

创建中间件,在响应返回前统一格式化JSON中的浮点数字段:

// app/Http/Middleware/FormatDecimal.php
namespace App\Http\Middleware;

use Closure;

class FormatDecimal
{
    public function handle($request, Closure $next)
    {
        $response = $next($request);
        
        // 处理JSON响应数据
        if (isset($response->original) && is_array($response->original)) {
            $this->formatNumbers($response->original);
        }
        
        return $response;
    }
    
    private function formatNumbers(&$data)
    {
        foreach ($data as &$value) {
            if (is_array($value)) {
                $this->formatNumbers($value);
            } elseif (is_numeric($value) && !is_int($value)) {
                $value = round($value, 5);
            }
        }
    }
}

然后在app/Http/Kernel.php的$routeMiddleware中注册这个中间件:

protected $routeMiddleware = [
    // 其他中间件
    'format.decimal' => \App\Http\Middleware\FormatDecimal::class,
];

最后给/api/invoices路由加上这个中间件:

Route::get('/api/invoices', [InvoiceController::class, 'index'])->middleware('format.decimal');

这样该路由返回的所有JSON数据里,浮点数字段都会被自动处理成5位小数。

内容的提问来源于stack exchange,提问作者Linesofcode

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 15:35:51