Java REST JAX-RS 2.0 –如何处理日期,时间和时间戳记数据类型

无论是X-Form-Urlencoded还是JSON HTTP发布到REST资源端点,对于与日期或时间相关的数据都没有特定的“数据类型”。 大多数开发人员会将这些数据发布为“字符串”,或者只是将它们转换为Unix时间戳值(例如1435061152)。 但是,随着开发人员实现越来越多的端点方法,将日期,时间和时间戳字符串表示值解析为实际java.sql.Date或java.util.Date的代码将是重复的(并且很无聊)。 因此,本文旨在说明如何在JAX-RS 2.0 REST端点方法参数中实现用于处理日期和时间相关的字符串值的自定义数据类型。

兼容性

该代码已通过Payara 4.1和Wildfly 8.2进行了测试。 对于其他其余的应用程序服务器和Servlet容器,需要JAX-RS 2.0库/ Java EE 7兼容性才能运行。

样品申请

为了演示这一点,让我们构建一个具有JAX-RS REST资源端点的示例应用程序,该端点通过@FormParam参数值获取自定义数据类型对象类,并将它们转换为java.sql.Datejava.sql.Timejava。 sql.Timestampjava.util.Date为方便起见。

HTTP POST请求示例

假设进行了以下URL的HTTP POST(使用“ SampleApplication ”作为应用程序名称,因此使用上下文):

http:// <主机名>:<端口> / SampleApplication / rest-api / request-handler / post-request-with-dates-and-time /

至于与此URL一起发布的HTTP参数,它们是:

发布参数 值(字符串) SimpleDateFormat模式 自定义数据类型类名称
date_field 1948-05-15 yyyy-MM-dd RESTDateParam
time_field 下午3:23 h:mma RESTTimeParam
timestamp_field 1979-10-11T14:45:00 yyyy-MM-dd'T'HH:mm:ss RESTTimestampParam
timestamp_with_tzd_field 1979-10-11T14:45:00 + 0800 yyyy-MM-dd'T'HH:mm:ssZ RESTTimestampWithTZDParam

实现自定义数据类型类

解析日期字符串值并将其转换为java.sql.Date

首先,让我们编写一个处理参数“ date_field ”的自定义数据类型类, 该类分析日期格式为yyyy-MM-dd的日期的字符串表示形式,并将其转换为java.sql.Date

RESTDateParam.java的代码

package com.developerscrappad;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.ws.rs.WebApplicationException;

public class RESTDateParam {

    // Declare the date format for the parsing to be correct
    private static final SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd" );
    private java.sql.Date date;

    /**
     * This is the default constructor which must take in one string parameter.
     * The parameter is no other than the one passed in through the REST
     * end-point. We'll see it later...
     */
    public RESTDateParam( String dateStr ) throws WebApplicationException {
        try {
            date = new java.sql.Date( df.parse( dateStr ).getTime() );
        } catch ( final ParseException ex ) {
            // Wrap up any expection as javax.ws.rs.WebApplicationException
            throw new WebApplicationException( ex );
        }
    }

    /**
     * This is a getter method which returns the parsed date string value as
     * java.sql.Date
     *
     */
    public java.sql.Date getDate() {
        return date;
    }

    /**
     * For convenience of result checking
     */
    @Override
    public String toString() {
        if ( date != null ) {
            return date.toString();
        } else {
            return "";
        }
    }
}

代码说明

在这里,我们首先为SimpleDateFormat定义适当的日期格式,例如“ yyyy-MM-dd”,以解析日期字符串。 调用构造函数后,在转换之后,我们就可以通过getDate()方法获取java.sql.Date对象。 除了java.sql.Date,您可能希望结果对象为java.util.Date或java.util.Calendar,这很好,这在很大程度上取决于应用程序的具体情况。 在这里,由于我们没有保留额外的时间和时区信息,因此只需一个简单的java.sql.Date就足够了。

对于下面其余的自定义数据类型类,则是如此。

解析时间字符串值(带有AM / PM指示器)并将其转换为java.sql.Time

RESTTimeParam.java的代码

package com.developerscrappad;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.ws.rs.WebApplicationException;

public class RESTTimeParam {

    private static final SimpleDateFormat df = new SimpleDateFormat( "h:mma" );
    private java.sql.Time time;

    public RESTTimeParam( String timeStr ) throws WebApplicationException {
        try {
            time = new java.sql.Time( df.parse( timeStr ).getTime() );
        } catch ( final ParseException ex ) {
            throw new WebApplicationException( ex );
        }
    }

    public java.sql.Time getTime() {
        return time;
    }

    @Override
    public String toString() {
        if ( time != null ) {
            return time.toString();
        } else {
            return "";
        }
    }
}

解析日期和时间字符串值并将其转换为java.sql.Timestamp

RESTTimestampParam.java的代码

package com.developerscrappad;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.ws.rs.WebApplicationException;

public class RESTTimestampParam {

    private static final SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss" );
    private java.sql.Timestamp timestamp;

    public RESTTimestampParam( String timestampStr ) throws WebApplicationException {
        try {
            timestamp = new java.sql.Timestamp( df.parse( timestampStr ).getTime() );
        } catch ( final ParseException ex ) {
            throw new WebApplicationException( ex );
        }
    }

    public java.sql.Timestamp getTimestamp() {
        return timestamp;
    }

    @Override
    public String toString() {
        if ( timestamp != null ) {
            return timestamp.toString();
        } else {
            return "";
        }
    }
}

解析时间字符串值(带有时区数据)并将其转换为java.util.Date(带有时区信息)

RESTTimestampWithTZDParam.java的代码

package com.developerscrappad;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import javax.ws.rs.WebApplicationException;

public class RESTTimestampWithTZDParam {

    private static final SimpleDateFormat df = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ssZ" );
    private java.util.Date date;

    public RESTTimestampWithTZDParam( String dateTimeStr ) throws WebApplicationException {
        try {
            date = new java.util.Date( df.parse( dateTimeStr ).getTime() );
        } catch ( final ParseException ex ) {
            throw new WebApplicationException( ex );
        }
    }

    public java.util.Date getDate() {
        return date;
    }

    @Override
    public String toString() {
        if ( date != null ) {
            return date.toString();
        } else {
            return "";
        }
    }
}

实施REST资源端点

因此,在定义了必要的自定义数据类型类以定义各种日期和时间格式之后,就进行了定义。 REST资源端点方法现在将能够使用这些类来封装给定的各种数据格式。 所有要做的就是直接将其用作端点方法参数的数据类型。 例如:

// ...
@POST
@Path( "/path-root/path-value" )
public Response methodThatHandlesPostRequest(
    @FormParam( "date_field" ) RESTDateParam dateField
) {
    // The rest of the implementation...
}
// ...

让我们看一个完整的JAX-RS 2.0 REST资源端点实现示例。

RESTResource.java的代码

package com.developerscrappad;

import javax.json.Json;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

@Path( "request-handler" )
public class RESTResource {

    @POST
    @Path( "post-request-with-custom-param-data-type" )
    @Produces( "application/json" )
    public Response postRequestWithCustomParamDataType(
        @FormParam( "date_field" ) RESTDateParam dateField, // Put the custom data type to good use
        @FormParam( "time_field" ) RESTTimeParam timeField,
        @FormParam( "timestamp_field" ) RESTTimestampParam timestampField,
        @FormParam( "timestamp_with_tzd_field" ) RESTTimestampWithTZDParam tsWithTZDField
    ) {
        // Output these data as JSON as server response
        String jsonResult = Json.createObjectBuilder()
            .add( "data_submitted", Json.createObjectBuilder()
                .add( "date_field", dateField.toString() )
                .add( "time_field", timeField.toString() )
                .add( "timestamp_field", timestampField.toString() )
                .add( "timestamp_with_tzd_field", tsWithTZDField.toString() )
            ).build().toString();

        return getNoCacheResponseBuilder( Response.Status.OK ).entity( jsonResult ).build();
    }

    /**
     * Say NO to result caching
     */
    protected ResponseBuilder getNoCacheResponseBuilder( Response.Status status ) {
        CacheControl cc = new CacheControl();
        cc.setNoCache( true );
        cc.setMaxAge( -1 );
        cc.setMustRevalidate( true );

        return Response.status( status ).cacheControl( cc );
    }
}

不要忘记扩展javax.ws.rs.core.Application的启动REST Application类。

RESTApplication的代码

package com.developerscrappad;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

@ApplicationPath( "rest-api" )
public class RESTApplication extends Application {

    public Set<Class<?>> getClasses() {
        return new HashSet<Class<?>>( Arrays.asList( RESTResource.class ) );
    }
}

使用jQuery Ajax POST通过HTML客户端进行测试

为了测试自定义数据类型类,使用jQuery编写了一个简单HTML页面,该页面对端点URL执行ajax HTTP POST。 只需将下面HTML文件打包为Web应用程序的一部分,以将其一起部署以进行测试。 请将其部署到适当的应用程序服务器或servlet容器中。

post-with-custom-param-data-type.html的代码

<!DOCTYPE html>
<html>
    <head>
        <title>Date, Time and Timestamp HTTP Post</title>
    </head>
    <body>
        <div>Date Field: <input id="dateField" type="text" value="1948-05-15" /> (format must be 'yyyy-MM-dd')</div>
        <div>Time Field: <input id="timeField" type="text" value="3:23PM" /> (format must be 'h:mma')</div>
        <div>Timestamp Field: <input id="timestampField" type="text" value="1979-10-11T14:45:00" style="width: 200px;" /> (format must be 'yyyy-MM-ddTHH:mm:ss')</div>
        <div>Timestamp With Time Zone Field: <input id="timestampWithTZDField" type="text" value="1979-10-11T14:45:00+0800" style="width: 200px;" /> (format must be 'yyyy-MM-ddTHH:mm:ss+/-HHmm')</div>
        <div><input type="button" value="Submit" οnclick="javascript:performSubmit();" /></div>
        <br /><br />
        <div id="resultJson"></div>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script type="text/javascript">
            var $ = jQuery.noConflict();

            function performSubmit() {
                $.ajax( {
                    url: "rest-api/request-handler/post-request-with-custom-param-data-type",
                    type: "POST",
                    data: {
                        "date_field": $.trim( $( "#dateField" ).val() ),
                        "time_field": $.trim( $( "#timeField" ).val() ),
                        "timestamp_field": $.trim( $( "#timestampField" ).val() ),
                        "timestamp_with_tzd_field": $.trim( $( "#timestampWithTZDField" ).val( ) )
                    },
                    success: function ( resultObj, textStatus, xhr ) {
                        $( "#resultJson" ).html( "<h2>Post Result (JSON)</h2>" + JSON.stringify( resultObj ) );
                    },
                    error: function ( xhr, textStatus, errorThrown ) {
                        $( "#resultJson" ).html( "Something went wrong, status " + xhr.status );
                    }
                } );
            }
        </script>
    </body>
</html>

结果

单击“ Submit ”按钮后,HTML客户端应从REST资源端点方法(路径:post-request-with-custom-param-data-type)接收正确的JSON响应,并显示在屏幕。

Java REST JAX-RS 2.0 –如何处理日期,时间和时间戳记数据类型

发布结果

就这样。 感谢您的阅读,希望对您有所帮助。

翻译自: https://www.javacodegeeks.com/2015/06/java-rest-jax-rs-2-0-how-to-handle-date-time-and-timestamp-data-types.html