您的位置:首页 > 编程语言 > Java开发

Struts2插件 —— struts2-json-plugin-2.x.x

2014-04-20 00:38 323 查看
为了方便AJAX与服务器进行数据交换,struts2中加入的json插件可用于对象的序列化和反序列化。

相关JAR包

struts2-json-plugin.2.x.x.jar

修改Struts2配置文件

更改package元素的extends属性

<span style="font-size:12px"><package name="default" extends="json-default"></span>  

配置result元素的type属性为json,将把Action中属性序列化返回

<span style="font-size:12px"><result type="json" /> </span>  

如果需要处理以JSON文本提交的请求,可在action元素中添加子元素interceptor引用JSON插件包中声明的拦截器:json。

<span style="font-size:12px"><interceptor-ref name="json" /></span>  

result type参数

result type对应的类为:org.apache.struts2.json.JSONInterceptor。下面是一些常用的result param:

root
<paramname="root">person</param>
excludeNullProperties 
是否去掉值为null的属性, 默认值为false。
<paramname="excludeNullProperties">true</param>
ignoreHierarchy 
是否忽略继承关系,ignoreHierarchy值默认为true。设置为false后,父类的属性也将被构建在JSON字符串中。
<paramname="ignoreHierarchy">false</param>
includeProperties
响应结果需要包含的属性值,支持正则表达式,可用","分隔以使用多个正则表达式匹配。
<paramname="includeProperties">person.*,
person\.name</param>
excludeProperties 
响应结果需要排除的属性值,支持正则表达式,可用“,”分隔以使用多个正则表达式匹配。
JSONInterceptor源码:

<span style="font-size:12px">/** 
 * Populates an action from a JSON string 
 */  
public class JSONInterceptor extends AbstractInterceptor {  
    private static final long serialVersionUID = 4950170304212158803L;  
    private static final Logger LOG = LoggerFactory.getLogger(JSONInterceptor.class);  
    private boolean enableSMD = false;  
    private boolean enableGZIP = false;  
    private boolean wrapWithComments;  
    private boolean prefix;  
    private String defaultEncoding = "ISO-8859-1";  
    private boolean ignoreHierarchy = true;  
    private String root;  
    private List<Pattern> excludeProperties;  
    private List<Pattern> includeProperties;  
    private boolean ignoreSMDMethodInterfaces = true;  
    private JSONPopulator populator = new JSONPopulator();  
    private JSONCleaner dataCleaner = null;  
    private boolean debug = false;  
    private boolean noCache = false;  
    private boolean excludeNullProperties;  
    private String callbackParameter;  
    private String contentType;  
  
    @SuppressWarnings("unchecked")  
    public String intercept(ActionInvocation invocation) throws Exception {  
        HttpServletRequest request = ServletActionContext.getRequest();  
        HttpServletResponse response = ServletActionContext.getResponse();  
        String contentType = request.getHeader("content-type");  
        if (contentType != null) {  
            int iSemicolonIdx;  
            if ((iSemicolonIdx = contentType.indexOf(";")) != -1)  
                contentType = contentType.substring(0, iSemicolonIdx);  
        }  
  
        Object rootObject = null;  
        if (this.root != null) {  
            ValueStack stack = invocation.getStack();  
            rootObject = stack.findValue(this.root);  
  
            if (rootObject == null) {  
                throw new RuntimeException("Invalid root expression: '" + this.root + "'.");  
            }  
        }  
  
        if ((contentType != null) && contentType.equalsIgnoreCase("application/json")) {  
            // load JSON object  
            Object obj = JSONUtil.deserialize(request.getReader());  
  
            if (obj instanceof Map) {  
                Map json = (Map) obj;  
  
                // clean up the values  
                if (dataCleaner != null)  
                    dataCleaner.clean("", json);  
  
                if (rootObject == null) // model overrides action  
                    rootObject = invocation.getStack().peek();  
  
                // populate fields  
                populator.populateObject(rootObject, json);  
            } else {  
                LOG.error("Unable to deserialize JSON object from request");  
                throw new JSONException("Unable to deserialize JSON object from request");  
            }  
        } else if ((contentType != null) && contentType.equalsIgnoreCase("application/json-rpc")) {  
            Object result;  
            if (this.enableSMD) {  
                // load JSON object  
                Object obj = JSONUtil.deserialize(request.getReader());  
  
                if (obj instanceof Map) {  
                    Map smd = (Map) obj;  
  
                    if (rootObject == null) // model makes no sense when using RPC  
                        rootObject = invocation.getAction();  
  
                    // invoke method  
                    try {  
                        result = this.invoke(rootObject, smd);  
                    } catch (Exception e) {  
                        RPCResponse rpcResponse = new RPCResponse();  
                        rpcResponse.setId(smd.get("id").toString());  
                        rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug()));  
  
                        result = rpcResponse;  
                    }  
                } else {  
                    String message = "SMD request was not in the right format. See http://json-rpc.org";  
  
                    RPCResponse rpcResponse = new RPCResponse();  
                    rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL));  
                    result = rpcResponse;  
                }  
            } else {  
                String message = "Request with content type of 'application/json-rpc' was received but SMD is "  
                        + "not enabled for this interceptor. Set 'enableSMD' to true to enable it";  
  
                RPCResponse rpcResponse = new RPCResponse();  
                rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED));  
                result = rpcResponse;  
            }  
  
            String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(),  
                    ignoreHierarchy, excludeNullProperties);  
            json = addCallbackIfApplicable(request, json);  
            boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request);  
            JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding,  
                    this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json"));  
  
            return Action.NONE;  
        } else {  
            if (LOG.isDebugEnabled()) {  
                LOG.debug("Content type must be 'application/json' or 'application/json-rpc'. " +  
                          "Ignoring request with content type " + contentType);  
            }  
        }  
  
        return invocation.invoke();  
    }  
  
    @SuppressWarnings("unchecked")  
    public RPCResponse invoke(Object object, Map data) throws IllegalArgumentException,  
            IllegalAccessException, InvocationTargetException, JSONException, InstantiationException,  
            NoSuchMethodException, IntrospectionException {  
  
        RPCResponse response = new RPCResponse();  
  
        // validate id  
        Object id = data.get("id");  
        if (id == null) {  
            String message = "'id' is required for JSON RPC";  
            response.setError(new RPCError(message, RPCErrorCode.METHOD_NOT_FOUND));  
            return response;  
        }  
        // could be a numeric value  
        response.setId(id.toString());  
  
        // the map is going to have: 'params', 'method' and 'id' (for the  
        // client to identify the response)  
        Class clazz = object.getClass();  
  
        // parameters  
        List parameters = (List) data.get("params");  
        int parameterCount = parameters != null ? parameters.size() : 0;  
  
        // method  
        String methodName = (String) data.get("method");  
        if (methodName == null) {  
            String message = "'method' is required for JSON RPC";  
            response.setError(new RPCError(message, RPCErrorCode.MISSING_METHOD));  
            return response;  
        }  
  
        Method method = this.getMethod(clazz, methodName, parameterCount);  
        if (method == null) {  
            String message = "Method " + methodName + " could not be found in action class.";  
            response.setError(new RPCError(message, RPCErrorCode.METHOD_NOT_FOUND));  
            return response;  
        }  
  
        // parameters  
        if (parameterCount > 0) {  
            Class[] parameterTypes = method.getParameterTypes();  
            Type[] genericTypes = method.getGenericParameterTypes();  
            List invocationParameters = new ArrayList();  
  
            // validate size  
            if (parameterTypes.length != parameterCount) {  
                // size mismatch  
                String message = "Parameter count in request, " + parameterCount  
                        + " do not match expected parameter count for " + methodName + ", "  
                        + parameterTypes.length;  
  
                response.setError(new RPCError(message, RPCErrorCode.PARAMETERS_MISMATCH));  
                return response;  
            }  
  
            // convert parameters  
            for (int i = 0; i < parameters.size(); i++) {  
                Object parameter = parameters.get(i);  
                Class paramType = parameterTypes[i];  
                Type genericType = genericTypes[i];  
  
                // clean up the values  
                if (dataCleaner != null)  
                    parameter = dataCleaner.clean("[" + i + "]", parameter);  
  
                Object converted = populator.convert(paramType, genericType, parameter, method);  
                invocationParameters.add(converted);  
            }  
  
            response.setResult(method.invoke(object, invocationParameters.toArray()));  
        } else {  
            response.setResult(method.invoke(object, new Object[0]));  
        }  
  
        return response;  
    }  
  
    @SuppressWarnings("unchecked")  
    private Method getMethod(Class clazz, String name, int parameterCount) {  
        Method[] smdMethods = JSONUtil.listSMDMethods(clazz, ignoreSMDMethodInterfaces);  
  
        for (Method method : smdMethods) {  
            if (checkSMDMethodSignature(method, name, parameterCount)) {  
                return method;  
            }  
        }  
        return null;  
    }  
  
    /** 
     * Look for a method in clazz carrying the SMDMethod annotation with 
     * matching name and parametersCount 
     *  
     * @return true if matches name and parameterCount 
     */  
    private boolean checkSMDMethodSignature(Method method, String name, int parameterCount) {  
  
        SMDMethod smdMethodAnntotation = method.getAnnotation(SMDMethod.class);  
        if (smdMethodAnntotation != null) {  
            String alias = smdMethodAnntotation.name();  
            boolean paramsMatch = method.getParameterTypes().length == parameterCount;  
            if (((alias.length() == 0) && method.getName().equals(name) && paramsMatch)  
                    || (alias.equals(name) && paramsMatch)) {  
                return true;  
            }  
        }  
  
        return false;  
    }  
  
    protected String addCallbackIfApplicable(HttpServletRequest request, String json) {  
        if ((callbackParameter != null) && (callbackParameter.length() > 0)) {  
            String callbackName = request.getParameter(callbackParameter);  
            if ((callbackName != null) && (callbackName.length() > 0))  
                json = callbackName + "(" + json + ")";  
        }  
        return json;  
    }  
  
    public boolean isEnableSMD() {  
        return this.enableSMD;  
    }  
  
    public void setEnableSMD(boolean enableSMD) {  
        this.enableSMD = enableSMD;  
    }  
  
    /** 
     * Ignore annotations on methods in interfaces You may need to set to this 
     * true if your action is a proxy/enhanced as annotations are not inherited 
     */  
    public void setIgnoreSMDMethodInterfaces(boolean ignoreSMDMethodInterfaces) {  
        this.ignoreSMDMethodInterfaces = ignoreSMDMethodInterfaces;  
    }  
  
    /** 
     * Wrap generated JSON with comments. Only used if SMD is enabled. 
     *  
     * @param wrapWithComments 
     */  
    public void setWrapWithComments(boolean wrapWithComments) {  
        this.wrapWithComments = wrapWithComments;  
    }  
  
    @Inject(StrutsConstants.STRUTS_I18N_ENCODING)  
    public void setDefaultEncoding(String val) {  
        this.defaultEncoding = val;  
    }  
  
    /** 
     * Ignore properties defined on base classes of the root object. 
     *  
     * @param ignoreHierarchy 
     */  
    public void setIgnoreHierarchy(boolean ignoreHierarchy) {  
        this.ignoreHierarchy = ignoreHierarchy;  
    }  
  
    /** 
     * Sets the root object to be deserialized, defaults to the Action 
     *  
     * @param root 
     *            OGNL expression of root object to be serialized 
     */  
    public void setRoot(String root) {  
        this.root = root;  
    }  
  
    /** 
     * Sets the JSONPopulator to be used 
     *  
     * @param populator 
     *            JSONPopulator 
     */  
    public void setJSONPopulator(JSONPopulator populator) {  
        this.populator = populator;  
    }  
  
    /** 
     * Sets the JSONCleaner to be used 
     *  
     * @param dataCleaner 
     *            JSONCleaner 
     */  
    public void setJSONCleaner(JSONCleaner dataCleaner) {  
        this.dataCleaner = dataCleaner;  
    }  
  
    /** 
     * @return true if debugging is turned on 
     */  
    public boolean getDebug() {  
        Boolean devModeOverride = FilterDispatcher.getDevModeOverride();  
        return devModeOverride != null ? devModeOverride.booleanValue() : this.debug;  
    }  
  
    /** 
     * Turns debugging on or off 
     *  
     * @param debug 
     *            true or false 
     */  
    public void setDebug(boolean debug) {  
        this.debug = debug;  
    }  
  
    @Inject(StrutsConstants.STRUTS_DEVMODE)  
    public void setDevMode(  
        String mode)  
    {  
        setDebug("true".equalsIgnoreCase(mode));  
    }  
  
    /** 
     * Sets a comma-delimited list of regular expressions to match properties 
     * that should be excluded from the JSON output. 
     *  
     * @param commaDelim 
     *            A comma-delimited list of regular expressions 
     */  
    public void setExcludeProperties(String commaDelim) {  
        Set<String> excludePatterns = JSONUtil.asSet(commaDelim);  
        if (excludePatterns != null) {  
            this.excludeProperties = new ArrayList<Pattern>(excludePatterns.size());  
            for (String pattern : excludePatterns) {  
                this.excludeProperties.add(Pattern.compile(pattern));  
            }  
        }  
    }  
  
    /** 
     * Sets a comma-delimited list of wildcard expressions to match 
     * properties that should be excluded from the JSON output. 
     *  
     * @param commaDelim 
     *            A comma-delimited list of wildcard expressions 
     */  
    public void setExcludeWildcards(String commaDelim) {  
        Set<String> excludePatterns = JSONUtil.asSet(commaDelim);  
        if (excludePatterns != null) {  
            this.excludeProperties = new ArrayList<Pattern>(excludePatterns.size());  
            for (String pattern : excludePatterns) {  
                this.excludeProperties.add(WildcardUtil.compileWildcardPattern(pattern));  
            }  
        }  
    }  
  
    /** 
     * Sets a comma-delimited list of regular expressions to match properties 
     * that should be included from the JSON output. 
     *  
     * @param commaDelim 
     *            A comma-delimited list of regular expressions 
     */  
    public void setIncludeProperties(String commaDelim) {  
        includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.REGEXP_PATTERN);  
    }  
  
    /** 
     * Sets a comma-delimited list of wildcard expressions to match 
     * properties that should be included from the JSON output.  The 
     * standard boilerplate (id, error, debug) are automatically included, 
     * as appropriate, so you only need to provide patterns for the 
     * contents of "result". 
     *  
     * @param commaDelim 
     *            A comma-delimited list of wildcard expressions 
     */  
    public void setIncludeWildcards(String commaDelim) {  
        includeProperties = JSONUtil.processIncludePatterns(JSONUtil.asSet(commaDelim), JSONUtil.WILDCARD_PATTERN);  
        if (includeProperties != null) {  
            includeProperties.add(Pattern.compile("id"));  
            includeProperties.add(Pattern.compile("result"));  
            includeProperties.add(Pattern.compile("error"));  
            includeProperties.add(WildcardUtil.compileWildcardPattern("error.code"));  
        }  
    }  
  
    /** 
     * Returns the appropriate set of includes, based on debug setting. 
     * Derived classes can override if there are additional, custom 
     * debug-only parameters. 
     */  
    protected List getIncludeProperties() {  
        if (includeProperties != null && getDebug()) {  
            List<Pattern> list = new ArrayList<Pattern>(includeProperties);  
            list.add(Pattern.compile("debug"));  
            list.add(WildcardUtil.compileWildcardPattern("error.*"));  
            return list;  
        } else {  
            return includeProperties;  
        }  
    }  
  
    public boolean isEnableGZIP() {  
        return enableGZIP;  
    }  
  
    /** 
     * Setting this property to "true" will compress the output. 
     *  
     * @param enableGZIP 
     *            Enable compressed output 
     */  
    public void setEnableGZIP(boolean enableGZIP) {  
        this.enableGZIP = enableGZIP;  
    }  
  
    public boolean isNoCache() {  
        return noCache;  
    }  
  
    /** 
     * Add headers to response to prevent the browser from caching the response 
     *  
     * @param noCache 
     */  
    public void setNoCache(boolean noCache) {  
        this.noCache = noCache;  
    }  
  
    public boolean isExcludeNullProperties() {  
        return excludeNullProperties;  
    }  
  
    /** 
     * Do not serialize properties with a null value 
     *  
     * @param excludeNullProperties 
     */  
    public void setExcludeNullProperties(boolean excludeNullProperties) {  
        this.excludeNullProperties = excludeNullProperties;  
    }  
  
    public void setCallbackParameter(String callbackParameter) {  
        this.callbackParameter = callbackParameter;  
    }  
  
    public String getCallbackParameter() {  
        return callbackParameter;  
    }  
  
    /** 
     * Add "{} && " to generated JSON 
     *  
     * @param prefix 
     */  
    public void setPrefix(boolean prefix) {  
        this.prefix = prefix;  
    }  
  
    public void setContentType(String contentType) {  
        this.contentType = contentType;  
    }  
}  
</span> 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: