为 Vaadin 8 Grid 实现列渲染器

2023-12-12

The 瓦丁框架指南有一个描述如何使用列渲染器的页面 in a 瓦丁网格. And 本页描述了渲染器的实现,但一切都太短暂了。

我想实施一个InstantRenderer补充 Vaadin 8.1 中添加的部分 java.time 渲染器集。添加了渲染器LocalDate & LocalDateTime但不是为了Instant, OffsetDateTime, and ZonedDateTime。为了我的Instant渲染器我目前只是应用当前的默认时区(ZoneId)得到一个ZonedDateTime我称之为toString方法。还可以做更多的事情,但这只是开始。

所以我的代码应该与提供的非常相似LocalDateTimeRenderer。我正在尝试遵循该代码作为指导。

在搜索 Vaadin 源代码并阅读文档时,我似乎需要三段源代码:

  • InstantRenderer( 如同LocalDateTimeRenderer )
  • InstantRendererConnector( 如同LocalDateTimeRendererConnector )
  • InstantRendererState( 如同LocalDateTimeRendererState )

我已经做到了这一点,并且一切都编译通过。但我的表格无法渲染,我得到的只是页面上的一个白色空框。控制台或日志上没有出现错误。如果我删除对我的使用InstantRenderer,然后回退到让我的Instant对象默认渲染它们自己的toString方法,一切顺利,表格按预期显示。所以我知道我的自定义渲染器有问题。

当谈到“服务器端”与“客户端”Vaadin 时,我是一个新手。

➠ 我需要执行某种包装吗?目前,我在 Vaadin 项目中开设了三门课程MyUI源文件。

➠ 我还漏掉了其他部分吗?

我通过调用无参数构造函数来实例化渲染器:

this.entriesGrid
    .addColumn( Entry::getStart )
    .setCaption( "Start" )
    .setRenderer( new InstantRenderer(  ) )
;

这是我上面列出的三个文件,几乎完全取自 Vaadin 源代码。

InstantRenderer

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package com.basil.timepiece;

import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;

import java.util.Locale;

import elemental.json.JsonValue;

/**
 * A renderer for presenting {@code Instant} objects.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
public class InstantRenderer
        extends com.vaadin.ui.renderers.AbstractRenderer< Object, Instant >
{
    private DateTimeFormatter formatter;
    private boolean getLocaleFromGrid;

    private ZoneId zoneId = ZoneId.systemDefault(); // Basil Bourque.

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the grid's locale it is
     * attached to, with the format style being {@code FormatStyle.LONG} for the
     * date and {@code FormatStyle.SHORT} for time, with an empty string as its
     * null representation.
     *
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#LONG">
     * FormatStyle.LONG</a>
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/FormatStyle.html#SHORT">
     * FormatStyle.SHORT</a>
     */
    public InstantRenderer ()
    {
        this( DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG , FormatStyle.SHORT ) , "" );
        getLocaleFromGrid = true;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter, with the
     * empty string as its null representation.
     *
     * @param formatter the formatter to use, not {@code null}
     * @throws IllegalArgumentException if formatter is null
     */
    public InstantRenderer ( DateTimeFormatter formatter )
    {
        this( formatter , "" );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given formatter.
     *
     * @param formatter          the formatter to use, not {@code null}
     * @param nullRepresentation the textual representation of the {@code null} value
     * @throws IllegalArgumentException if formatter is null
     */
    public InstantRenderer ( DateTimeFormatter formatter , String nullRepresentation )
    {
        super( Instant.class , nullRepresentation );

        if ( formatter == null )
        {
            throw new IllegalArgumentException( "formatter may not be null" );
        }

        this.formatter = formatter;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the grid's locale it is attached to, with an empty string as
     * its null representation.
     *
     * @param formatPattern the format pattern to format the date with, not {@code null}
     * @throws IllegalArgumentException if format pattern is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern )
    {
        this( formatPattern , Locale.getDefault() );
        getLocaleFromGrid = true;
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the given locale, with an empty string as its null
     * representation.
     *
     * @param formatPattern the format pattern to format the date with, not {@code null}
     * @param locale        the locale to use, not {@code null}
     * @throws IllegalArgumentException if format pattern is null
     * @throws IllegalArgumentException if locale is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern , Locale locale )
    {
        this( formatPattern , locale , "" );
    }

    /**
     * Creates a new InstantRenderer.
     * <p>
     * The renderer is configured to render with the given string format, as
     * displayed in the given locale.
     *
     * @param formatPattern      the format pattern to format the date with, not {@code null}
     * @param locale             the locale to use, not {@code null}
     * @param nullRepresentation the textual representation of the {@code null} value
     * @throws IllegalArgumentException if format pattern is null
     * @throws IllegalArgumentException if locale is null
     * @see <a href=
     * "https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#patterns">
     * Format Pattern Syntax</a>
     */
    public InstantRenderer ( String formatPattern , Locale locale , String nullRepresentation )
    {
        super( Instant.class , nullRepresentation );

        if ( formatPattern == null )
        {
            throw new IllegalArgumentException( "format pattern may not be null" );
        }

        if ( locale == null )
        {
            throw new IllegalArgumentException( "locale may not be null" );
        }

        formatter = DateTimeFormatter.ofPattern( formatPattern , locale );
    }

    @Override
    public JsonValue encode ( Instant value )
    {
        String dateString;
        if ( value == null )
        {
            dateString = this.getNullRepresentation();
        } else if ( this.getLocaleFromGrid )
        {
            if ( null == this.getParentGrid() )
            {
                throw new IllegalStateException(
                        "Could not find a locale to format with: "
                                + "this renderer should either be attached to a grid "
                                + "or constructed with locale information" );
            }
            ZonedDateTime zdt = value.atZone( this.zoneId );  // Basil Bourque.
            Locale locale = this.getParentGrid().getLocale();
            dateString = zdt.format( formatter.withLocale( locale ) );
        } else
        {
            ZonedDateTime zdt = value.atZone( this.zoneId );  // Basil Bourque.
            dateString = zdt.format( formatter );
        }
        return encode( dateString , String.class );
    }

    @Override
    protected InstantRendererState getState ()
    {
        InstantRendererState s = ( InstantRendererState ) super.getState();
        return s;
    }

    @Override
    protected InstantRendererState getState ( boolean markAsDirty )
    {
        InstantRendererState s = ( InstantRendererState ) super.getState( markAsDirty );
        return s;
    }
}

InstantRendererConnector

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.basil.timepiece;

import com.vaadin.shared.ui.Connect;

/**
 * A connector for InstantRenderer.
 * <p>
 * The server-side Renderer operates on {@code Instant}s, but the data is
 * serialized as a string, and displayed as-is on the client side. This is to be
 * able to support the server's locale.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
@Connect( InstantRenderer.class )
public class InstantRendererConnector extends com.vaadin.client.connectors.grid.TextRendererConnector
{

    @Override
    public InstantRendererState getState ()
    {
        return ( InstantRendererState ) super.getState();
    }
}

InstantRendererState

/*
 * By Basil Bourque. Taken almost entirely from source code published by Vaadin Ltd.
 *
 * --------
 *
 * Copyright 2000-2016 Vaadin Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.basil.timepiece;

/**
 * Shared state of InstantRenderer.
 *
 * @author Vaadin Ltd
 * @since 8.1
 */
public class InstantRendererState extends com.vaadin.shared.ui.grid.renderers.TextRendererState
{
    // This code intentionally left blank.
}

来源:BitBucket

我已经发布了我的BitBucket 上完整的 Maven 驱动项目,列渲染器的所有必需文件Instant, OffsetDateTime, and ZonedDateTime.

功能要求

我已经发布问题#10208为 Vaadin Grid 的其他 java.time 类型(Instant、OffsetDateTime、ZonedDateTime)实现列渲染器,以补充 Vaadin 8.1 中的 LocalDate 和 LocalDateTime 渲染器。在 Vaadin 框架 GitHub 页面上。


需要特殊包装

是的,需要特殊包装。你不能简单地扔掉Vaadin 网格列渲染器实现课程进入常规 Vaadin 应用程序。

列渲染器实现所需的三个类中的两个涉及客户端开发,而不是通常的服务器端开发我们通常在 Vaadin 应用程序中进行工作。

幸运的是,这比听起来更容易。为了做一个简单的列渲染器,Vaadin 幸运地提供了一些超类来完成大部分繁重的工作。所以我们不需要了解所有血淋淋的细节GWT and JavaScript瓦丁的幕后魔法正在发生。

成功之路包括:

  • 使用 Vaadin 提供的模板创建一个单独的项目来构建您自己的项目Vaadin 附加组件.
  • 使用来自的源代码填充该项目瓦丁框架GitHub项目.

vaadin-archetype-widget

使用开始一个新项目多模块 Maven 原型Vaadin 团队提供:vaadin-archetype-widget见于这个清单.

screen shot of IntelliJ > New Project > Create from archetype dialog box

addon module

一旦您根据该原型创建了一个项目IDE,添加您的三列渲染器类,如本屏幕截图所示Instant渲染器。

  • Renderer类位于“addon”模块的主包中。
  • RendererConnector & RendererState类文件位于“addon”模块的嵌套中client包裹。

当然,在实际工作中你会删除这个例子MyComponent…由原型创建的文件。

demo module

构建完成后,您可以通过导入“addon”模块的包在“demo”模块的 Vaadin 应用程序中尝试列渲染器。在这种情况下:

import org.basilbourque.timecolrenderers.InstantRenderer;

GitHub 源码

我成功实施了Instant列渲染器完全取自三个LocalDateTimeRendererVaadin 8.1.3 源代码中提供了相关类。您可以通过键入找到这些类的当前版本LocalDateTimeRenderer in the GitHub 查找文件功能.

enter image description here

  • shared/src/main/java/com/vaadin/shared/ui/grid/renderers/LocalDateTimeRendererState.java
  • server/src/main/java/com/vaadin/ui/renderers/LocalDateTimeRenderer.java
  • client/src/main/java/com/vaadin/client/connectors/grid/LocalDateTimeRendererConnector.java

screen shot of 'Project' pane in IntelliJ showing the position of three Java source files within the package hierarchy

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为 Vaadin 8 Grid 实现列渲染器 的相关文章

  • Vaadin 7 在执行后台线程后不刷新 UI(仅当需要超过 5 分钟时)

    我正在使用 Vaadin 7 在我的应用程序中 有一个表格列表 用户可以选择一个或多个项目来详细说明 如果单击执行按钮 UI 组件将被禁用并启动两个线程 第一个线程执行繁重的计算 第二个线程更新 UI 上的进度指示器 使用 lock 和un
  • 将 DataGridView 导出到 Excel 的简单方法

    我正在尝试将 DataGridView 数据复制到 Excel 并且使用以下代码 public static void ExportToExcel DataGridView dgView Microsoft Office Interop E
  • Java jTable 定义单元格上的颜色行更改

    大家好 我没有发现下面的代码有什么不正确的地方 它可以很好地填充表格和标题 然而 当我改变第 1 行 第 1 列 to test然后单击它不会像我预期的那样为该行着色 然后单击我单击的那个会变成绿色 从那时起我单击桌子上的任何地方都会变成绿
  • WPF:将 DataGrid 绑定到列表

    有趣的是 有时简单的事情会在背后咬我一口 我可以使用 DataGridTextColumn 将 DataGrid 很好地绑定到某个任意类的集合 如下所示 bound to List
  • Vaadin 14 组合框选择鼠标悬停时的工具提示

    我正在使用 Vaadin 14 Java 我有一个带有枚举的组合框作为可能的选择项 我想在组合框中显示枚举作为可能的选择 但我想在鼠标悬停 工具提示上显示较长的属性 名称 我看到旧版本的 Vaadin 也存在同样的问题 显然没有解决方案 并
  • 如何将editedRows从DataGrid MUI更新到firebase?

    如何将刚刚编辑的值更新到 firebase 到目前为止 这是我从 editRow 中了解到的 如果我错了 请纠正我 数据网格内部 Enable edit mode for row and not cell editMode row any
  • Vaadin 更改默认会话过期通知?

    瓦丁7 6 2 如何更改默认的会话过期通知 消息和通知类型 要更改会话过期消息 您需要创建自己的SystemMessagesProvider 您在其中定义它 例如 在 Servlet 部署中 您可以执行以下操作 WebServlet url
  • 如何在vaadin中播放视频?

    我使用了两个视频组件 Video video new Video 并嵌入 Embedded embed new Embedded my video new ExternalResource yyy xxx mp4 embed setMime
  • DataGrid 格式中的 WPF RichTextBox 混乱

    我需要在 DataGrid 的列中使用 RichTextBox 这是通过 xaml 完成的
  • WPF Datagrid - 如何验证多行并标记所有无效行?

    我有一个包含行的数据网格 其中验证取决于他的兄弟姐妹 到目前为止 我正在使用 BindingGroups 和自定义 ValidationRule 同时验证多行 但我不知道如何更改无效行条目的外观 我返回一个 ValidationResult
  • 一次性渲染阴影

    考虑到阴影投射的成本 我想知道对于动态定位的静态对象 例如 程序城市 是否有一个功能或可能 实验性的方法可以在 Three js 中仅渲染一次阴影贴图 甚至在 webgl 中 因此 结果可以在静态对象的下一帧中免费使用 仅当物体移动时才会进
  • 将 WPF DataGrid 导出到 Excel

    当我将 DataGrid 导出到 Excel 时 为什么我的值会发生变化 字符串 351732051316944 变为 3 51732E 14 和我的日期时间 2014 01 01 02 09 29 942 变为 41641 09035 我
  • 数据网格中的主键始终为零

    我们正在VS2012中使用实体框架 DB First 开发WPF应用程序 我们在数据网格视图中遇到问题 我们从数据源中拖动了一个数据网格 这创建了一个绑定到该特定表的数据网格 该表有两列 一列是 TransporterID 它是 PK 是自
  • ASP.NET 2.0 - 带有 tbody / thead 的 DataGrid

    有没有办法让 DataGrid 控件呈现 tbody 和 thead HTML 元素 虽然我喜欢 user186197 的答案 但该博客文章使用反射 但在非完全信任的托管环境中可能会出现问题 这是我们使用的 没有黑客 public clas
  • 如何在代码中访问 DataGridCell 的数据对象?

    基本上 我已经绑定了数据网格 使其类似于科目时间表 每行代表一个学期的科目 该学期内的每个单元格代表一个科目 我现在尝试添加拖放功能 以便您可以将其他主题拖到网格上 这将更新底层数据结构 我可以使用一些可视化树方法来查找用户将新主题拖动到的
  • 了解用户是否更改了 DataGrid 中的数据的最佳方法是什么?

    我想知道每次用户修改 WPF DataGrid 中的数据时 我可以使用一个事件来做到这一点吗 或者我可以用来覆盖全套数据更改 添加行 删除行 修改行等 的最小事件集是什么 我知道这可能超出了你的要求 但是一旦你这样做了 就很难回头了 无论您
  • WPF DataGridTemplateColumn 标题绑定不起作用

    我将 DataGrid 与一些手动创建的 DataGridTemplateColumns 一起使用 这是工作中的代码片段
  • 在 Dojo 数据网格中添加一行

    努力寻找一些易于理解的代码 如何在 Dojo 数据网格 版本 1 4 2 中添加行并清除所有行 假设数据有 2 列 其中包含客户 ID 和地址 我在用 dojo data ItemFileWriteStore 存储值 但再次不太确定应该如何
  • 如何使用 ViewModel 对 silverlight 数据网格实现自然(人类字母数字)排序?

    在使用数据网格的 silverlight 项目中 我使用一些定义 标签编号 的列 它是一个 Varchar 我想按照自然排序顺序对此列进行排序 如中所述 http www interact sw co uk iangblog 2007 12
  • 通过样式设置 DataGridCellsPresenter 的 ItemsPanel 不起作用

    我正在尝试设置ItemsPanel of a DataGridCellsPresenter在我的窗口的资源中 Bu

随机推荐

  • 所有分区的eekToEnd并在Kafka消费者的自动重新平衡中幸存

    当消费者组 A 的 Kafka 消费者连接到 Kafka 代理时 我想查找所有分区的末尾 即使偏移量存储在代理端 如果有更多额外的消费者连接同一消费者组 他们应该获取最新存储的偏移量 我正在做以下事情 consumer poll timeo
  • 检测到互联网连接时下载数据

    我想在互联网连接可用时下载一些数据 包括 json 和图像 二进制数据 我有一个完整的工作代码可以做到这一点 问题是我已经在自定义应用程序类中编写了该代码 它会下载它并保存在本地 但是当应用程序启动时 互联网连接可能在那时不可用 因此 我想
  • 如何更改 iframe 的方向

    就我而言 我已将另一个组织 是的 我被授权这样做 开发的 html 游戏嵌入到网站中 页面和 HTML 游戏文件位于同一域中 该游戏是为支持 iPad 而开发的 但仅限横向 然而 在 iframe 中 它总是显示 请使用横向方向 的消息 即
  • 从命令行守护程​​序使用 MLMediaLibrary 时出现 XPC 错误

    我正在编写一个命令行守护程 序来从 iPhoto 读取图像 我可以初始化并加载MLMediaLibrary从使用 Xcode 项目创建工具创建的成熟 Cocoa 应用程序中得到的结果很好 但是 当我尝试从命令行工具 也在 Xcode 中创建
  • PHP脚本中的内存泄漏

    我有一个 php 脚本 它运行 mysql 查询 然后循环结果 并在该循环中还运行多个查询 sqlstr SELECT FROM user pred WHERE uprType 2 AND uprTurn turn ORDER BY upr
  • 如何根据动态变量进行匹配?

    是否可以匹配动态变量而不仅仅是文字 在此代码中 第一个match应该和注释掉的一样match number 0 being 0 and number 1 being 1 const NUMBERS i8 2 0 1 fn test let
  • 使用 Python 代替 AppleScript

    我经常使用 Applescript 来完成基本任务 例如打开和关闭程序 有时会更深入一些 例如运行特定 Xcode 程序的单元测试 我正在学习Python 我喜欢它 我还没有找到太多有关 AppleScript 和 Python 的文档 我
  • Hadoop 中的 setJarByClass()

    在 Hadoop 算法的驱动程序方法中的某个时刻 我们将作业链接到设置为 Mapper 和Reducer 的类的引用 例如 job setMapperClass MyMapper class job setReducerClass MyRe
  • 如何将 Python2 中的 all: print "string" 替换为:Python3 中的 print("string")? [复制]

    这个问题在这里已经有答案了 正如标题所说 如何将 Python2 中的 all print string 替换为 Python3 中的 print string I really希望他们使这一功能向后兼容 官方推荐使用 2to3 py 脚本
  • 使用实体框架自引用树的最有效方法

    所以我有一个 SQL 表 基本上是 ID ParentID MenuName Lineage Depth 最后两列是自动计算的 以帮助搜索 因此我们现在可以忽略它们 我正在创建一个具有多个类别的下拉菜单系统 不幸的是 我认为 EF 不能很好
  • 使用 xslt 排序对给定顺序进行排序

    我在用着
  • 从 Firebase 获取一个值并将其更新为当前值 + 1

    所以是的 标题有问题 一些信息 这是我的 Firebase 数据库的样子 这是当前的代码 export function updateQTY barcode database ref items barcode update qty cur
  • 如何检测无符号整数溢出?

    I was writing a program in C to find all solutions of ab c where a b and c together use all the digits 0 9 exactly once
  • 替换 pandas dataframe 列中的前 n 个元素

    我想更换第一个n我的数据框中的一列元素与我保存的另一个 pd series 举个例子 category price store testscore 0 Cleaning 11 42 Walmart NaN 1 Cleaning 23 50
  • R - 给定奥尔森时区的 UTC 到 LOCAL 时间

    我有 1974 2013 年的时间序列数据 其中有一列为 datetimeUTC YYYY MM DD hh mm 0000 一列为 Olson 格式的时区 例如 加拿大 太平洋 加拿大 东部 我可以将整个 UTCdatetime 列转换为
  • ListView WP8 中的增量加载

    我读过有关如何在滚动到列表视图底部时进行增量加载的文章 以及如何在滚动到列表顶部时实现延迟加载的文章 当用户到达顶部时 我想将更多项目添加到列表顶部 我们有什么办法可以实现这一目标吗 为此找到了解决方案 旋转两个控件 对于例如 gt
  • 2个php.ini文件

    我发现 当我在终端上输入以下内容时 php i grep php ini 我得到输出 加载的配置文件是 etc php5 cli php ini 然而 从phpinfo 我看到 加载的ini文件是 etc php5 apache2 php
  • Facebook API 限制

    我正在使用应用程序中的 Facebook Graph 和 FQL API 经过 OAuth 身份验证 我在文档中找不到有关速率限制 节流的任何内容 通常 我期望类 用户有某种限制 查看 Facebook 应用程序页面 Insigths gt
  • 如何使用node js将消息从Web服务器推送到浏览器

  • 为 Vaadin 8 Grid 实现列渲染器

    The 瓦丁框架指南有一个描述如何使用列渲染器的页面 in a 瓦丁网格 And 本页描述了渲染器的实现 但一切都太短暂了 我想实施一个InstantRenderer补充 Vaadin 8 1 中添加的部分 java time 渲染器集 添