2012-03-01 26 views
37

Tôi có một dịch vụ được định nghĩa như sau.CXF JAXRS - Làm cách nào để chuyển Ngày làm QueryParam

public String getData(@QueryParam("date") Date date)

Tôi đang cố gắng để vượt qua một java.util.Date đến nó từ khách hàng của tôi (đó là jaxrs: client của CXF, không phải là một khách hàng HTTP generic hoặc trình duyệt).

Dịch vụ của tôi nhận được ngày là Thu Mar 01 22:33:10 IST 2012 trong URL HTTP. Vì CXF sẽ không thể tạo đối tượng Date bằng Chuỗi này, khách hàng của tôi sẽ nhận được lỗi 404. Tôi đã thử sử dụng một số ParameterHandler ở phía dịch vụ, nhưng tôi vẫn không thể phân tích cú pháp thành công vì tôi không mong đợi ngày ở bất kỳ định dạng cụ thể nào.

Theo this post, chuyển một số Date được cho là hoạt động ngoài hộp, nhưng dường như tôi không thể làm việc cơ bản. Tôi có phải làm bất cứ điều gì để truyền thành công đối tượng Date từ khách hàng của tôi đến dịch vụ không? Đánh giá cao bất kỳ trợ giúp nào.

Cảm ơn

+0

Không chắc chắn ý của bạn là gì bởi 'kết quả trong ngày được gửi là Thu Mar 01 22:33:10 IST 2012', vì bạn đang * nhận * ngày, không * gửi * một. Đảm bảo rằng URL bạn đang gọi được mã hóa chính xác trước khi gọi nó. – Perception

+0

Đã chỉnh sửa bài đăng để làm rõ. URL được mã hóa chính xác. Khách hàng của tôi đang gửi tham số ngày là 'Thu Mar 01 22:33:10 IST 2012' và dịch vụ của tôi cũng nhận được thông báo đó. Tuy nhiên, ngày ở định dạng không thể phân tích cú pháp (nếu tôi sử dụng ParameterHandler) hoặc không thể sử dụng bởi CXF để trực tiếp tạo đối tượng Date. – domino

+0

Điều đó làm cho mọi việc rõ ràng hơn. Dẫn đến câu hỏi tiếp theo - là phương pháp này dự kiến ​​cũng sẽ có thể xử lý ngày ở định dạng khác (tiêu chuẩn hơn)? – Perception

Trả lời

51

Vấn đề là JAX-RS dictates rằng tham số unbundling được thực hiện theo một trong hai cách sau:

  1. bean tham số có một constructor nào chấp nhận một String
  2. Tham số đậu có phương thức tĩnh valueOf(String).

Trong trường hợp của bạn, Ngày được bỏ nhóm thông qua công cụ xây dựng Date(String), không thể xử lý định dạng đầu vào mà khách hàng của bạn đang gửi. Bạn có một vài tùy chọn có sẵn để khắc phục điều này:


Lựa chọn 1

Nhận khách hàng của bạn để thay đổi định dạng ngày trước khi họ gửi đi. Đây là lý tưởng, nhưng có lẽ là khó khăn nhất để hoàn thành!


Lựa chọn 2

Xử lý định dạng ngày điên. Các tùy chọn cho điều này là:

Thay đổi chữ ký phương thức của bạn để chấp nhận một chuỗi. Cố gắng xây dựng một đối tượng Date trong số đó và nếu điều đó không thành công, hãy sử dụng lớp SimpleDateFormat tùy chỉnh của riêng bạn để phân tích nó.

static final DateFormat CRAZY_FORMAT = new SimpleDateFormat(""); 

public String getData(@QueryParam("date") String dateString) { 
    final Date date; 
    try { 
     date = new Date(dateString); // yes, I know this is a deprecated method 
    } catch(Exception e) { 
     date = CRAZY_FORMAT.parse(dateString); 
    } 
} 

Xác định lớp tham số của riêng bạn mà không logic nêu trên. Cung cấp cho nó một hàm tạo chuỗi hoặc phương thức tĩnh valueOf(String) gọi logic. Và một phương pháp bổ sung để có được ngày khi tất cả được nói và thực hiện.

public class DateParameter implements Serializable { 
    public static DateParameter valueOf(String dateString) { 
     try { 
      date = new Date(dateString); // yes, I know this is a deprecated method 
     } catch(Exception e) { 
      date = CRAZY_FORMAT.parse(dateString); 
     } 
    } 

    private Date date; 
    // Constructor, Getters, Setters 
} 

public String getData(@QueryParam("date") DateParameter dateParam) { 
    final Date date = dateParam.getDate(); 
} 

Hoặc cuối cùng, bạn có thể đăng ký một handler tham số cho những ngày. Trường hợp logic của nó chỉ đơn giản là giống như đã đề cập cho các tùy chọn khác ở trên. Lưu ý rằng bạn cần phải sử dụng ít nhất CXF 2.5.3 để có trình xử lý tham số được đánh giá trước khi nó thử logic mặc định không được gộp.

public class DateHandler implements ParameterHandler<Date> { 
    public Map fromString(String s) { 
     final Date date; 
     try { 
      date = new Date(dateString); // yes, I know this is a deprecated method 
     } catch(Exception e) { 
      date = CRAZY_FORMAT.parse(dateString); 
     } 
    } 
} 
+0

Reg. Tùy chọn # 1: Trong trường hợp này, tôi tự phân phối khách hàng cho người dùng, vì vậy tôi tự do chọn định dạng ngày cố định nếu có. Nhưng câu hỏi là, làm thế nào để tôi làm điều này một cách chính xác? Điều gì xác định định dạng mà khách hàng CXF sẽ sử dụng? Tôi vẫn muốn giữ 'java.util.Date' là 'QueryParam' thay vì thay đổi thành' String' hoặc 'DateParam' khác như đối tượng để đóng gói một đối tượng' Date' bên trong. – domino

+0

Vâng, nếu bạn có quyền kiểm soát khách hàng làm cho mọi thứ tốt hơn. Chỉ cần truyền vào bất kỳ định dạng ngày nào có thể được xử lý bởi hàm tạo 'Date (String)'. Ví dụ là '12/20/2005 09:30:00 +0100 '(mm/dd/yyy HH: MM: ss Z). – Perception

+1

Tôi có quyền kiểm soát đối với ứng dụng khách, nhưng chữ ký của tôi trên cả phía máy khách và dịch vụ phải là 'Ngày'. Từ phía máy khách, CXF ** nội bộ ** gọi 'toString()' trên đối tượng 'Date' trong khi xây dựng tham số truy vấn, làm cách nào để kiểm soát và sử dụng định dạng ngày cụ thể chứ không phải định dạng ngày mặc định? Bạn có gợi ý mở rộng 'Date' và ghi đè' toString() '(có nghĩa là chữ ký của khách hàng sẽ thay đổi)? Hoặc có cơ chế nào khác có thể được sử dụng trên cả phía máy khách và dịch vụ để ghi đè hành vi không? Tôi đoán 'MessageBodyReader/Wrtier' chỉ dành cho thân yêu cầu. – domino

0

Như @Perception gợi ý trong lựa chọn hai, bạn có thể xử lý ngày tháng. Nhưng bạn nên sử dụng sau đây:

private Date getDateFromString(String dateString) { 
    try { 
     DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); 
     Date date = df.parse(dateString); 
     return date; 
    } catch (ParseException e) { 
     //WebApplicationException ...("Date format should be yyyy-MM-dd'T'HH:mm:ss", Status.BAD_REQUEST); 
    } 
} 

Bạn gọi nó từ bên trong tài nguyên như

Date date = getDateFromString(dateString);//dateString is query param. 
1

Sử dụng một lớp tùy chỉnh DateParam dường như tùy chọn an toàn nhất. Sau đó, bạn có thể căn cứ vào các chữ ký phương thức của bạn trên đó và thực hiện logic chuyển đổi xấu xí bên trong phương thức valueOf() hoặc hàm tạo lớp. Nó cũng là nhiều tự chủ tài liệu vì sử dụng dây đồng bằng

9

Percepiton's answer là rất hữu ích, nhưng ParameterHandler đã bị phản đối trong Apache-CXF 3.0, xem Apache-cxf 3.0 Migration Guide:

CXF JAX-RS ParameterHandler đã được giảm xuống, hãy sử dụng JAX-RS 2.0 ParamConverterProvider.

Vì vậy, tôi thêm một ví dụ với các ParamConverterProvider:

public class DateParameterConverterProvider implements ParamConverterProvider { 

    @Override 
    public <T> ParamConverter<T> getConverter(Class<T> type, Type type1, Annotation[] antns) { 
     if (Date.class.equals(type)) { 
      @SuppressWarnings("unchecked") 
      ParamConverter<T> paramConverter = (ParamConverter<T>) new DateParameterConverter(); 
      return paramConverter; 
     } 
     return null; 
    } 

} 

public class DateParameterConverter implements ParamConverter<Date> { 

    public static final String format = "yyyy-MM-dd"; // set the format to whatever you need 

    @Override 
    public Date fromString(String string) { 
     SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format); 
     try { 
      return simpleDateFormat.parse(string); 
     } catch (ParseException ex) { 
      throw new WebApplicationException(ex); 
     } 
    } 

    @Override 
    public String toString(Date t) { 
     return new SimpleDateFormat(format).format(t); 
    } 

} 

Các @SuppressWarnings là cần thiết để ngăn chặn một "hoạt động đánh dấu hoặc không an toàn" cảnh báo trong quá trình biên dịch. Xem How do I address unchecked cast warnings để biết thêm chi tiết.

ParamConverterProvider có thể được đăng ký là nhà cung cấp. Đây là cách tôi đã làm điều đó:

<jaxrs:server id="myService" address="/rest"> 
     <jaxrs:serviceBeans> 
      ... 
     </jaxrs:serviceBeans> 

     <jaxrs:providers> 
      <ref bean="dateParameterConverterProvider" /> 
     </jaxrs:providers> 
    </jaxrs:server> 

    <bean id="dateParameterConverterProvider" class="myPackage.DateParameterConverterProvider"/> 

Xem Apache-cxf JAX-RS : Services Configuration để biết thêm thông tin.

Các vấn đề liên quan