【问题标题】:Struts2 REST plugin: Sending JSON object through PUTStruts2 REST 插件:通过 PUT 发送 JSON 对象
【发布时间】:2019-03-29 00:24:34
【问题描述】:

我正在使用 Struts2 和 Struts2 REST 插件编写一个 RESTful 服务。目前,我的服务能够毫无问题地处理 GET 请求,但我一直试图让它“更新”(PUT)请求工作。

我有两个可能的模型,一个用于 show() 的 List 和一个用于 update() 的 ClientFeature 对象,其中 ClientFeature 是一个 pojo 类。

REST 控制器:

public class ClientfeatureController extends ControllerParent implements ModelDriven<Object> {

    private ClientFeature clientFeature = new ClientFeature();
    private List<ClientFeature> clientFeatureList;

    //Client ID
    private String id;

    public ClientfeatureController() {
        super(ClientfeatureController.class);
    }

    @Override
    public Object getModel() {
        return (clientFeatureList != null ? clientFeatureList : clientFeature);
    }

    /**
     * @return clientFeatureList through Struts2 model-driven design
     */
    public HttpHeaders show() {
        -logic for GET request here..-
        //todo: add ETag and lastModified information for client caching purposes
        return new DefaultHttpHeaders("show").disableCaching();
    }

    // PUT request: /clientfeature/update/<id> + JSON data
    public String update() {
        logger.info("client id: " + id);
        logger.info("updated model test:" + clientFeature.getClientId());
        return "update";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<ClientFeature> getClientFeatureList() {
        return clientFeatureList;
    }

    public void setClientFeatureList(List<ClientFeature> clientFeatureList) {
        this.clientFeatureList = clientFeatureList;
    }
}

客户端功能:

    public class ClientFeature {
    private Long clientId;
    private Feature feature;
    private ArrayList<String> countries;

    public ClientFeature() {
        this.countries = new ArrayList<String>();
    }

    public Long getClientId() {
        return clientId;
    }

    public void setClientId(Long clientId) {
        this.clientId = clientId;
    }

    public Feature getFeature() {
        return feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }

    public ArrayList<String> getCountries() {
        return countries;
    }

    public void setCountries(ArrayList<String> countries) {
        this.countries = countries;
    }
}

并且正在使用 chrome 的 Postman 扩展测试该服务,并发送类似于以下内容的 JSON 数据:

{
 "clientFeature": {
   "feature" : {"featureId" : 999, "featureName" : "testFeature"}
   "countries": ["CA","US"]
   "clientId" : 001
 }
}

还有错误:

356572 [http-bio-8080-exec-6] WARN  net.sf.json.JSONObject  - Tried to assign property clientFeature:java.lang.Object to bean of class com.foo.bar.ClientFeature

我对所有相关的东西都非常陌生,因此非常感谢任何帮助。

编辑:

尝试发送以下 JSON:

{ “com.foo.entity.clientFeature”:{“clientId”:10} }

并得到以下完整错误:

1016894 [http-bio-8080-exec-3] ERROR freemarker.runtime  - Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object

Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object
The problematic instruction:
----------
==> ${msg[0]} [on line 68, column 29 in org/apache/struts2/dispatcher/error.ftl]
----------

Java backtrace for programmers:
----------
freemarker.template.TemplateModelException: Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object
    at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:130)
    at freemarker.ext.beans.SimpleMethodModel.get(SimpleMethodModel.java:138)
    at freemarker.core.DynamicKeyName.dealWithNumericalKey(DynamicKeyName.java:111)
    at freemarker.core.DynamicKeyName._getAsTemplateModel(DynamicKeyName.java:90)
    at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
    at freemarker.core.Expression.getStringValue(Expression.java:93)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IfBlock.accept(IfBlock.java:82)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:179)
    at freemarker.core.Environment.visit(Environment.java:417)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:102)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IfBlock.accept(IfBlock.java:82)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.Environment.process(Environment.java:190)
    at freemarker.template.Template.process(Template.java:237)
    at org.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:797)
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:519)
    at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:851)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:278)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.NullPointerException
    at freemarker.ext.beans.SimpleMemberModel.unwrapArguments(SimpleMemberModel.java:85)
    at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:106)
    ... 43 more

【问题讨论】:

    标签: java json rest struts2 struts2-json-plugin


    【解决方案1】:

    通过使用正确的 JSON 语法解决了问题..

    如果有人遇到类似问题,在我的情况下,正确的语法是:

    {clientFeature: {"feature":{"id":3,"enabled":true,"description":"description here","type":"FEATURE_TYPE_HERE"},"countries":["SG"],"clientId":10}}
    

    【讨论】:

      【解决方案2】:

      我想解释一下我在使用 Strtus2 rest 插件开发 API 时发现了什么。你应该了解 rest 插件如何管理我们暴露给外部世界的 bean(json、xml 等)

      我已经坚持了一天来弄清楚我的 json 波纹管如何无法正确转换为我的 bean 列表。

      所以,这是我的 json 字符串:

      { 
      "messagesList": [{
          "id": "E57EC40F",
          "body": "Ok!",
          ... other_property
      },{
          "id": "25B42CC8CCE57EC40F",
          "body": "Testing",
          ... other_property
      }],
      "ackList": [{
          "id": "5B42CC8CCE57EC40F",
          "queueNumber": 100,
          "chatId": "3434",
          "status": "delivered"
      },{
          "id": "E6A25B42CC8CCE57EC40F",
          "queueNumber": 100,
          "chatId": "1747",
          "status": "viewed"
      }]
      }
      

      有了这个 json,我假设我可以通过添加属性获取并自动将这个 json 转换到我的列表中

       List<OurModel> messageList;
       List<OurModel> ack;
      

      在我的控制器中。所以我的错误控制器看起来像这样:

      
      
      @ParentPackage("api-pesan")
      @Namespace("/api/pesan")
          public class RetrieveMessageApi implements ModelDriven<Object> {
          @Autowired
          WebHookService webHookService;
      
          Object retModal;
          List<OurModel> messagesList;
          List<OurModel> ack;
          public HttpHeaders create() throws IOException {
      
              System.out.println(messagesList.toString());
      
              System.out.println(ack.toString());
      
              return new DefaultHttpHeaders("create");
          }
      
      
          public Object getModel() {
              return model;
          }
      
      //setter and getter
      
       }
      
      

      如果你假设你可以在 create 方法中打印 messagesList 和 ack 属性,那你就错了。我被困了一天才能弄清楚。这是我关于如何将 json 发布到我们的 strtus2 REST 插件的解释。

      首先,struts2中的rest插件在检索对象并将对象返回到外部restful url时,只读取对象(属性名,也是对象作为类型)。

      到那时,我创建了我的类 (pojo) 来包装我的列表。这个类是这样的

      
      public class WrapperModel implements Serializable {
      
          private List<YourObject> messages;
          private List<YourObject> ack;
      
      //setter getter
      
      }
      

      你会注意到,我们的 json 结构看起来和这个类一样。所以这是我完整且成功的控制器类,它可以获取 json 并正确绑定到我们的属性。

      @ParentPackage("api-pesan")
      public class RetrieveMessageApi implements ModelDriven<Object> {
      
          @Autowired
          WebHookService webHookService;
      
          Object model = new WrapperModel();
      
          public HttpHeaders create() throws IOException {
      
              System.out.println(model.toString());
      
      
              return new DefaultHttpHeaders("create");
          }
      
      
      
          public Object getModel() {
              return model;
          }
      
      }
      
      

      然后尝试通过http://localhost:8080/app/api/api-pesan/retrieve-message.json 和方法 post 发送 json,也可以将您的 json 作为正文。

      结果,您将在日志控制台上看到来自我们的 json 的属性中的列表字符串。

      谢谢,希望对大家有所帮助....

      【讨论】:

        猜你喜欢
        • 2012-09-30
        • 2016-01-30
        • 1970-01-01
        • 2012-10-22
        • 2014-10-05
        • 1970-01-01
        • 2019-08-24
        • 1970-01-01
        • 2016-06-22
        相关资源
        最近更新 更多