Будь то отправка HTTP-сообщения X-Form-Urlencoded или JSON в конечную точку ресурса REST, для данных, относящихся к дате или времени, не существует определенного «типа данных». Большинство разработчиков будут публиковать эти данные как «String» или просто конвертировать их в значение метки времени Unix (например, 1435061152). Но по мере того, как разработчики внедряют все больше и больше методов конечной точки, коды для анализа значений представления строки даты, времени и метки времени в реальных java.sql.Date или java.util.Date будут повторяться (и скучно). Итак, цель этой статьи — показать, как реализовать пользовательский тип данных для обработки строковых значений, связанных с датой и временем, в параметрах метода конечной точки REST JAX-RS 2.0.
Совместимость
Коды были протестированы с Payara 4.1 и Wildfly 8.2. Для остальных серверов приложений и контейнеров сервлетов для этого требуется совместимость библиотек JAX-RS 2.0 / Java EE 7.
Образец заявки
Чтобы продемонстрировать это, давайте создадим пример приложения, которое имеет конечную точку ресурса JAX-RS REST, которая принимает классы объектов пользовательских типов данных через значения параметров @FormParam и преобразует их в java.sql.Date , java.sql.Time , java. sql.Timestamp и java.util.Date для удобства.
Пример HTTP-запроса POST
Скажем, HTTP POST из приведенного ниже URL сделан (с SampleApplication в качестве имени приложения и, следовательно, контекста):
Http: // <имя хоста>: <порт> / SampleApplication / отдых-апи / запрос обработчика / пост-запрос-с даты-времени и /
Что касается параметров HTTP, которые будут опубликованы вместе с этим URL, они:
Параметры сообщения | Значение (Строка) | Шаблон SimpleDateFormat | Пользовательский тип данных Имя класса |
---|---|---|---|
date_field | 1948-05-15 | YYYY-MM-дд | RESTDateParam |
time_field | 3:23 вечера | ч: мин | RESTTimeParam |
timestamp_field | 1979-10-11T14: 45: 00 | YYYY-MM-dd’T’HH: мм: сс | RESTTimestampParam |
timestamp_with_tzd_field | 1979-10-11T14: 45: 00 + 0800 | YYYY-MM-dd’T’HH: мм: SSZ | RESTTimestampWithTZDParam |
Реализация классов пользовательских типов данных
Разбор значения строки даты и преобразование его в java.sql.Date
Во-первых, давайте напишем пользовательский класс типов данных, который обрабатывает параметр date_field , который анализирует строковое представление даты в формате yyyy-MM-dd и превращает его в java.sql.Date .
Коды для RESTDateParam.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
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 для анализа строки даты. После того как конструктор был вызван и после преобразования мы можем получить объект java.sql.Date с помощью метода getDate () . Помимо java.sql.Date, вы можете захотеть, чтобы результирующий объект был либо java.util.Date, либо java.util.Calendar, и это нормально, что во многом зависит от специфики приложения. Здесь, поскольку мы не храним дополнительную информацию о времени и часовом поясе, достаточно простой java.sql.Date.
Как и для остальных классов пользовательских типов данных ниже.
Разбор значения строки времени (с индикатором AM / PM) и преобразование его в java.sql.Time
Коды для RESTTimeParam.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
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 теперь сможет использовать эти классы для инкапсуляции данных в различных форматах. Все, что нужно сделать, это использовать его непосредственно как тип данных аргументов метода конечной точки. Например:
1
2
3
4
5
6
7
8
9
|
// ... @POST @Path ( "/path-root/path-value" ) public Response methodThatHandlesPostRequest( @FormParam ( "date_field" ) RESTDateParam dateField ) { // The rest of the implementation... } // ... |
Давайте посмотрим на полный пример реализации конечной точки ресурса REST JAX-RS 2.0.
Коды для RESTResource.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
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 ); } } |
Не забывая инициирующий класс Приложения REST, который расширяет javax.ws.rs.core.Application…
Коды для RESTApplication
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
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 ) ); } } |
Тестирование через клиент HTML с помощью jQuery Ajax POST
Чтобы протестировать классы пользовательских типов данных, была написана простая HTML-страница с использованием jQuery, который выполняет HTTP-запрос POST ajax к URL-адресу конечной точки. Просто упакуйте приведенный ниже HTML-файл как часть веб-приложения, которое будет развернуто для тестирования. Пожалуйста, разверните это на соответствующем сервере приложений или в контейнере сервлетов.
Коды для post-with-custom-param-data-type.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<! 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" onclick = "javascript:performSubmit();" /></ div > < br />< br /> < div id = "resultJson" ></ div > < 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 > |
Результат
После нажатия кнопки « Отправить » клиент HTML должен получить законный ответ JSON от метода конечной точки ресурса REST (путь: post-request-with-custom-param-data-type) и отобразиться в нижней части экран.
Это все. Спасибо за чтение и надеюсь, что это поможет.
Ссылка: | Java REST JAX-RS 2.0 — Как обрабатывать типы данных даты, времени и метки времени от нашего партнера по JCG Макса Лэма в блоге разработчика Scrappad . |