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

Laravel9 如何实现单控制器数据全局共享至所有视图

Laravel全局存储跨请求搜索数据最佳实践

针对跨视图复用搜索结果、保留搜索输入的需求,不要使用视图变量共享、容器单例这类仅支持单次请求生命周期的方案,最合适的实现方式是基于Session做用户级状态存储,配合全局视图共享实现全页面复用,具体实现步骤如下:

一、先修复现有代码的基础问题

你当前代码有三个容易出问题的点:

  • 表单路由调用错误:路由命名为search,表单里写route('/search')会报路由不存在错误,应该改为route('search')
  • 直接返回视图不符合PRG规范:POST请求后直接返回视图,用户刷新页面会触发重复提交弹窗,应该用重定向返回目标页面
  • 客户端ID是唯一标识,查询用first()返回单条数据即可,不需要用get()返回集合

二、核心实现逻辑

Session是Laravel提供的用户级跨请求存储机制,数据和单个用户绑定,不会出现不同用户数据串扰的问题,完全匹配你的需求:

  • 搜索提交后把客户端ID、查询结果存入Session,跨页面跳转不会丢失
  • 重复搜索相同ID时直接复用Session内数据,无需重复查询数据库
  • 全局把Session内的搜索数据共享给所有视图,不需要每个控制器单独传值
  • 搜索框直接读取Session内存储的客户端ID做值回填,切换页面也能保留输入内容

三、具体代码实现

1. 改造搜索控制器

<?php

namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function get_kcli(Request $request)
    {
        $kcli = $request->input('kcli');
        $targetRoute = $request->input('currentPage');

        // 搜索值为空时清除已存储的搜索状态
        if (empty($kcli)) {
            $request->session()->forget(['current_client_id', 'current_client_data']);
            return redirect()->route($targetRoute);
        }

        // Session中已存在相同ID的搜索结果,直接跳转不重复查库
        if ((int)session('current_client_id') === (int)$kcli) {
            return redirect()->route($targetRoute);
        }

        // 查询客户端数据
        $clientData = DB::connection('oracle')
            ->table('CLIENTS')
            ->where('KCLI', $kcli)
            ->first();

        // 未查到数据返回错误提示
        if (!$clientData) {
            return back()->withErrors(['kcli' => "未找到ID为{$kcli}的客户端"]);
        }

        // 搜索结果写入Session
        session([
            'current_client_id' => $kcli,
            'current_client_data' => $clientData
        ]);

        return redirect()->route($targetRoute);
    }
}

2. 新增全局中间件共享视图变量

不要直接在AppServiceProvider里做视图共享,服务提供者启动时Session还未初始化,会读不到数据,通过中间件共享更稳妥:
首先执行artisan命令生成中间件:
php artisan make:middleware ShareSearchData

编辑app/Http/Middleware/ShareSearchData.php文件:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\View;

class ShareSearchData
{
    public function handle(Request $request, Closure $next)
    {
        // 把搜索数据共享给所有视图,所有模板可直接调用变量
        View::share('currentClientId', session('current_client_id'));
        View::share('currentClient', session('current_client_data'));

        return $next($request);
    }
}

打开app/Http/Kernel.php,把中间件注册到web中间件组,注意要放在StartSession中间件后面:

protected $middlewareGroups = [
    'web' => [
        // 其他原有中间件...
        \Illuminate\Session\Middleware\StartSession::class,
        // 新增这行注册共享中间件
        \App\Http\Middleware\ShareSearchData::class,
        // 其他原有中间件...
    ],
];

3. 改造搜索表单组件

修复路由错误,增加搜索值回填、错误提示,移除多余的@method('POST')声明(表单默认提交方式就是POST):

<nav class="navbar navbar-light">
<form method="POST" class="form-inline position-relative" action="{{ route('search') }}">
    @csrf
    <input 
        class="form-control shadow-none" 
        name="kcli" 
        id="kcli" 
        type="number" 
        placeholder="Codice..." 
        aria-label="Search"
        value="{{ $currentClientId ?? '' }}"
    >
    <input type="text" name="currentPage" value="{{ Route::currentRouteName() }}" hidden>
    <button type="submit" class="btn btn-light search-btn"><i class="fas fa-search"></i></button>
    @error('kcli')
        <div class="text-danger small position-absolute" style="top:100%;left:0">{{ $message }}</div>
    @enderror
</form>
</nav>

四、使用方式

改造完成后,你在任意视图文件里都可以直接调用两个变量:

  • $currentClientId:当前搜索的客户端ID,搜索框回填就是用这个值
  • $currentClient:对应客户端的全量数据,不需要每个控制器单独查询、传值,只要用户不修改搜索条件、不手动清空搜索,切换任意页面都能直接读取,不会重复查询数据库。

可选性能优化

如果单条客户端数据字段多、体积大,不想把全量数据存在Session里,可以只在Session里存客户端ID,把中间件的逻辑改成带全局缓存的查询,多个用户搜索同一个客户端ID可以共用缓存,进一步减少数据库查询:

// ShareSearchData中间件handle方法内逻辑替换
$clientId = session('current_client_id');
$currentClient = null;

if ($clientId) {
    // 客户端数据缓存24小时,表数据更新时可以手动清除对应缓存
    $currentClient = cache()->remember("client_info_{$clientId}", 86400, function() use ($clientId) {
        return DB::connection('oracle')->table('CLIENTS')->where('KCLI', $clientId)->first();
    });
}

View::share('currentClientId', $clientId);
View::share('currentClient', $currentClient);

对应控制器里只需要存current_client_id到Session即可,不需要存全量数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 00:48:23