Будь то отправка 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 . |
