2016-09-20 3 views
1

스트럿츠 버전 : 2.5.2Struts2 나머지 매퍼가 아닌 나머지 JSON 결과 인계

Struts의 종속성

<dependency> 
    <groupId>org.apache.struts</groupId> 
    <artifactId>struts2-core</artifactId> 
    <version>${org.strutsframework-version}</version> 
</dependency> 


<dependency> 
    <groupId>org.apache.struts</groupId> 
    <artifactId>struts2-convention-plugin</artifactId> 
    <version>${org.strutsframework-version}</version> 
</dependency> 

<dependency> 
    <groupId>org.apache.struts</groupId> 
    <artifactId>struts2-rest-plugin</artifactId> 
    <version>${org.strutsframework-version}</version> 
</dependency> 

<dependency> 
    <groupId>org.apache.struts</groupId> 
    <artifactId>struts2-spring-plugin</artifactId> 
    <version>${org.strutsframework-version}</version> 
</dependency> 

스트럿츠 XML

<?xml version="1.0" encoding="UTF-8"?> 

<!DOCTYPE struts PUBLIC 
     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" 
     "http://struts.apache.org/dtds/struts-2.3.dtd"> 

<struts> 
    <!-- Tell jinjava where the templates are --> 
    <constant name="struts.jinjava.basepath" value="WEB-INF/jinjava" /> 
    <!-- custom jinjava tags specific to iws --> 
    <constant name="struts.jinjava.scan.tagPackage" value="com.hs.iws.jinjava.tag" /> 
    <constant name="struts.jinjava.scan.functionPackage" value="com.hs.iws.jinjava.function" /> 

    <!--Tell struts to use the REST action Mapper--> 
    <!--<constant name="struts.mapper.class" value="rest"/>--> 

    <!-- allow rest and non rest actions to live together --> 
    <constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" /> 
    <constant name="struts.mapper.prefixMapping" value=":rest,/grid:struts"/> 
    <constant name="struts.rest.namespace" value="/" /> 

    <constant name="struts.convention.action.suffix" value="Action"/> 
    <constant name="struts.convention.action.mapAllMatches" value="true"/> 
    <constant name="struts.convention.package.locators.basePackage" value="com.hs.iws.actions" /> 

    <!--re-assert the extensions for struts that have been over written by the rest plugin--> 
    <constant name="struts.action.extension" value="xhtml,,json,action"/> 
    <constant name="struts.rest.content.restrictToGET" value="false" /> 

    <!--configure Convention Plugin to find our controllers--> 
    <constant name="struts.convention.default.parent.package" value="iws-default"/> 

    <!-- Spring Configuration --> 
    <!-- <constant name="struts.objectFactory" value="spring" /> --> 
    <constant name="struts.objectFactory.spring.autoWire" value="type" /> 


    <!-- all grid actions should fall under this package --> 
    <package name="iws-grid" namespace="/grid" extends="struts-default,jweb-struts-gson-json,jinjava,datatables"> 
     <interceptors> 

      <interceptor-stack name="iws-datatable-stack"> 
       <interceptor-ref name="exception"/> 
       <interceptor-ref name="alias"/> 
       <interceptor-ref name="servletConfig"/> 
       <interceptor-ref name="i18n"/> 
       <interceptor-ref name="prepare"/> 
       <interceptor-ref name="chain"/> 
       <interceptor-ref name="datetime"/> 
       <interceptor-ref name="staticParams"/> 
       <interceptor-ref name="actionMappingParams"/> 
       <interceptor-ref name="params"/> 
       <interceptor-ref name="gson-json" /> 
       <interceptor-ref name="workflow"> 
        <param name="excludeMethods">input,back,cancel,browse</param> 
       </interceptor-ref> 
       <interceptor-ref name="debugging"/> 
      </interceptor-stack> 

     </interceptors> 

     <default-interceptor-ref name="iws-datatable-stack" /> 
    </package> 


    <package name="iws-default" extends="rest-default, struts-default, jinjava, jweb-struts-gson-json" namespace="/"> 


    </package> 
</struts> 

액션 POM에서 클래스

package com.hs.iws.actions; 

import com.hs.datatables.DataTable10CriteriaQuery; 
import com.hs.datatables.DataTable10Helper; 
import com.hs.iws.model.Users; 
import org.apache.struts2.convention.annotation.*; 

/** 
* Created by Paul on 9/14/2016. 
*/ 
@InterceptorRef(value = "iws-datatable-stack") 
@ParentPackage(value = "iws-grid") 
public class TestGridAction extends DataTable10CriteriaQuery{ 

    @Action(value="/test-grid-json", 
      results={ 
        @Result(name = "success", type = "datatable") 
      } 
    ) 
    public String execute() { 
     return super.execute(); 
    } 

    @Override 
    protected Class<?> getHibernateClass() { 
     return Users.class; 
    } 
} 

DataTables JS 라이브러리로 작업 중이며 그리드에 대한 작업을 작성하려고합니다. 이미 저를 위해 json을 생성하는 API를 가지고 있으며, 단지 그것을 다시 스트리밍해야합니다. 이 문제를 처리하기 위해 사용자 지정 결과를 만들었지 만 작업에 매핑 된 결과는 실행되지 않습니다. 결과 유형이 무엇이든 REST 매퍼는 application/json이 클라이언트에서 요청 된 것을 확인하자마자 처리하려고 시도합니다. 구성에서 접두사 매핑을 사용하여 모든 URL에/grid를 사용하여 나머지 매퍼를 무시하도록했습니다. 올바른 인터셉터 스택을 실행하고 @Action 주석 정보를 사용하여 URL을 매핑하므로 일부 용량에서 작동하는 것 같습니다. 그러나 지정된 결과는 실행 중이 지 않으며받은 스택 추적을 기반으로 나머지 매퍼가 대신 제공합니다./grid 네임 스페이스의 모든 작업에 대해 나머지 매퍼를 완전히 무시하고 싶습니다. 내가 그 작업에 대한 요청에 여전히 휴식을 초래하는 구성에서 잘못된 것을 수행 했습니까?

스택 추적은

ERROR RestActionInvocation Exception processing the result. 
net.sf.json.JSONException: java.lang.reflect.InvocationTargetException 
    at net.sf.json.JSONObject._fromBean(JSONObject.java:987) 
    at net.sf.json.JSONObject.fromObject(JSONObject.java:168) 
    at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:265) 
    at net.sf.json.JSONArray._processValue(JSONArray.java:2514) 
    at net.sf.json.JSONArray.processValue(JSONArray.java:2539) 
    at net.sf.json.JSONArray.addValue(JSONArray.java:2526) 
    at net.sf.json.JSONArray._fromCollection(JSONArray.java:1057) 
    at net.sf.json.JSONArray.fromObject(JSONArray.java:123) 
    at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:237) 
    at net.sf.json.JSONObject._processValue(JSONObject.java:2808) 
    at net.sf.json.JSONObject.processValue(JSONObject.java:2874) 
    at net.sf.json.JSONObject.setInternal(JSONObject.java:2889) 
    at net.sf.json.JSONObject.setValue(JSONObject.java:1577) 
    at net.sf.json.JSONObject._fromBean(JSONObject.java:934) 
    at net.sf.json.JSONObject.fromObject(JSONObject.java:168) 
    at net.sf.json.AbstractJSON._processValue(AbstractJSON.java:265) 
    at net.sf.json.JSONObject._processValue(JSONObject.java:2808) 
    at net.sf.json.JSONObject.processValue(JSONObject.java:2874) 
    at net.sf.json.JSONObject.setInternal(JSONObject.java:2889) 
    at net.sf.json.JSONObject.setValue(JSONObject.java:1577) 
    at net.sf.json.JSONObject._fromBean(JSONObject.java:934) 
    at net.sf.json.JSONObject.fromObject(JSONObject.java:168) 
    at net.sf.json.JSONObject.fromObject(JSONObject.java:130) 
    at org.apache.struts2.rest.handler.JsonLibHandler.fromObject(JsonLibHandler.java:72) 
    at org.apache.struts2.rest.DefaultContentTypeHandlerManager.handleResult(DefaultContentTypeHandlerManager.java:181) 
    at org.apache.struts2.rest.RestActionInvocation.executeResult(RestActionInvocation.java:227) 
    at org.apache.struts2.rest.RestActionInvocation.processResult(RestActionInvocation.java:194) 
    at org.apache.struts2.rest.RestActionInvocation.invoke(RestActionInvocation.java:142) 
    at com.opensymphony.xwork2.DefaultActionProxy.execute(DefaultActionProxy.java:154) 
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:556) 
    at org.apache.struts2.dispatcher.ExecuteOperations.executeAction(ExecuteOperations.java:81) 
    at org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:113) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) 
    at com.hs.security.SecurityScanner.doFilter(SecurityScanner.java:95) 
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) 
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199) 
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:105) 
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506) 
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) 
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) 
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) 
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) 
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1078) 
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) 
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:760) 
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1524) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
    at java.lang.Thread.run(Thread.java:745) 
Caused by: java.lang.reflect.InvocationTargetException 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:497) 
    at org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(PropertyUtilsBean.java:2116) 
    at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1267) 
    at org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(PropertyUtilsBean.java:808) 
    at org.apache.commons.beanutils.PropertyUtilsBean.getProperty(PropertyUtilsBean.java:884) 
    at org.apache.commons.beanutils.PropertyUtils.getProperty(PropertyUtils.java:464) 
    at net.sf.json.JSONObject._fromBean(JSONObject.java:918) 
    ... 52 more 
Caused by: java.lang.UnsupportedOperationException: JsonObject 
    at com.google.gson.JsonElement.getAsByte(JsonElement.java:257) 
    ... 62 more 
+0

".action"을 사용하여 작업을 호출하면 올바른 결과를 호출한다는 것을 알았습니다. 그게 필요한지 확실하지 않은가요? 어쩌면 누군가가 그것에 대해 더 많은 것을 밝힐 수 있습니다. –

+0

일부 디버거 도구 –

+0

https://struts.apache.org/docs/rest-plugin.html#RESTPlugin-RESTandnon-RESTfulURL%27sTogetherConfiguration을 사용하십시오. –

답변

1

나는 비슷한 문제로 실행했습니다. 먼저 struts2-rest-plugin이 json 이상을 반환 할 수 있다는 것을 이미 알고 있으므로 xml 및 xhtml을 반환 할 수 있습니다 (URL의 파일 확장명을 전환하여). 결과가 작동하지 않는 성가신 이유는 strtus2-rest-plugin이 결과를 사용하지 않지만 결과를 사용하려는 시도를 대체하는 ContentTypeHandlers를 사용한다는 것입니다.

당신의 경우에는 .action 접미사가 나머지 플러그인을 방해하므로 아마도 다른 오래된 일치하는 액션을 찾아 볼 수 있습니다.

내 자신의 코드에서이 문제를 해결할 수있는 평안하고 비 안정적인 패키지를 만들었습니다. 또한 자신의 기본값을 바꾸기 위해 내 자신의 content-type 처리기를 만들어야했습니다. 사용자 정의 결과를 사용자 정의 컨텐츠 유형 핸들러로 바꿀 수는 있지만, "xml, json 또는 xhtml"유형이 아닌 한 비 안정 패키지를 작성하고이를 사용하여 해당 조치를 구현하는 것이 더 적합합니다 .

오늘 밤에 두 세트의 패키지를 만드는 데 사용되는 struts.xml 사본을 제공 할 것입니다. struts2-rest-plugin의 설정이 깨지기 쉽고 (직관적이지 않고, 논리보다 추측하여 더 많이 추가 된 줄을 필요로하기 때문에) 유용하기 때문에 유용 할 것입니다.

<?xml version="1.0" encoding="UTF-8" ?> 
<!DOCTYPE struts PUBLIC 
    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" 
    "http://struts.apache.org/dtds/struts-2.5.dtd"> 
<struts> 
    <constant name="struts.devMode" value="true" /> 
    <!-- the next two lines are ONLY if you want to override a content handler, and since mine is custom it would be with your own impl, however without pain you can only overrride because I think think the extensions are hard coded... so you can't just add your own, could be wrong --> 
    <bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="flexjson" class="com.kenmcwilliams.s2.result.FlexJsonHandler" /> 
    <constant name="struts.rest.handlerOverride.json" value="flexjson"/> 

    <constant name="struts.action.extension" value="xhtml,,xml,json,action"/> 
    <constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" /> 
    <constant name="struts.mapper.prefixMapping" value="/rest:rest,:struts"/> 
    <constant name="struts.convention.action.mapAllMatches" value="true"/> 
    <constant name="struts.convention.default.parent.package" value="my-conventions"/> 
    <constant name="struts.rest.namespace" value="/rest"/> 

    <package name="my-conventions" namespace="/" extends="convention-default" > 
     <result-types> 
      <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/> 
     </result-types> 
     <!-- Following is required for some reason --> 
     <global-allowed-methods>execute,input,back,cancel,browse,save,delete,list,index,show,create,update,destroy,edit,editNew</global-allowed-methods> 
    </package> 

    <package name="my-rest" namespace="/rest" extends="rest-default"> 
     <result-types> 
      <result-type name="flexjson" class="com.kenmcwilliams.s2.result.FlexJsonResult"/> 
     </result-types> 
    </package> 

    <!-- not needed unless you're planning on using tiles --> 
    <package name="my-tiles" namespace="/tiles" extends="tiles-default" strict-method-invocation="false"> 
     <result-types> 
      <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/> 
     </result-types> 
    </package> 
</struts> 
+0

'PrefixBasedActionMapper'가'ContentTypeHandler' 전에 요청을 처리하지 않아야합니까? 예,'PrefixBasedActionMapper'를 사용하여 별도의 패키지가 필요하지만 사용자 정의 컨텐츠 유형 핸들러를 작성할 필요가 없습니다. 플러그인 구성이 매우 직관적이지는 않지만 문서에서 복사하여 붙여 넣기 만하면 필요한 것을 얻을 수 있다고 동의하십시오. –

+0

struts2-rest-plugin을 사용하는 경우 해당 규칙을 사용하여 작업을 매핑하므로 규칙을 사용하여 컨텐트를 생성하는 방법을 재정의 할 수 없습니다. 그것의 행동을 오버라이드하는 유일한 방법은 custom-content-type을 사용하는 것입니다. 그것은 커다란 고통입니다. – Quaternion

+0

나머지 플러그인이 여전히 결과를 처리하는 이유를 파악하기에 신중하게 보지 못했지만, 언급 한대로 나중에 예제를 제공 할 것입니다.이 두 가지를 비교할 수 있습니다. – Quaternion