AEM dropdown select by servlet

转载自:AEM - Touch UI dropdown from JSON file/Servlet
自己查了一下午资料,不如别人给的一份有用。

代码


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.ValueFormatException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceMetadata;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.adobe.cq.commerce.common.ValueMapDecorator;
import com.adobe.granite.ui.components.ds.DataSource;
import com.adobe.granite.ui.components.ds.EmptyDataSource;
import com.adobe.granite.ui.components.ds.SimpleDataSource;
import com.adobe.granite.ui.components.ds.ValueMapResource;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import static org.apache.sling.api.servlets.ServletResolverConstants.SLING_SERVLET_RESOURCE_TYPES;

@Component(service = Servlet.class,
        property = {
                Constants.SERVICE_ID + "=" + "Dynamic DataSource Servlet",
                SLING_SERVLET_RESOURCE_TYPES + "=" + "/apps/aemtutorials/dropdowns"//如果路径不同,则不会触发该Servlet
        })
public class DynamicDataSourceServlet extends SlingSafeMethodsServlet {
    private static final long serialVersionUID = 1L;
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response)
            throws ServletException, IOException {
        try {
            ResourceResolver resolver = request.getResourceResolver();
            Resource currentResource = request.getResource();
            // set fallback
            request.setAttribute(DataSource.class.getName(), EmptyDataSource.instance());

            //Get json path through datasource options
            String jsonStr = null;
            Resource datasource = currentResource.getChild("datasource");
            Object options = datasource.getValueMap().get("options");
            Resource jsonResource = resolver.getResource(options.toString()+"/jcr:content");
            jsonStr = getJsonFromFile(jsonResource);//Json to String

            Gson gson = new Gson();
            TypeToken<List<Option>> token = new TypeToken<List<Option>>(){};

            List<Option> optionList = gson.fromJson(jsonStr, token.getType());
            List<Resource> optionResourceList = new ArrayList<Resource>();

            Iterator<Option> oi = optionList.iterator();
            while (oi.hasNext()) {
                Option opt = oi.next();
                ValueMap vm = getOptionValueMap(opt);//Option to ValueMap
                optionResourceList
                        .add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm));
            }

            DataSource ds = new SimpleDataSource(optionResourceList.iterator());
            request.setAttribute(DataSource.class.getName(), ds);

        } catch (IOException io) {
            logger.info("Error fetching JSON data ");
            io.printStackTrace();
        } catch (Exception e) {
            logger.info("Error in Getting Drop Down Values ");
            e.printStackTrace();
        }
    }

    private ValueMap getOptionValueMap(Option opt) {
        ValueMap vm = new ValueMapDecorator(new HashMap<String, Object>());

        vm.put("value", opt.getValue());
        vm.put("text", opt.getText());
        if (opt.isSelected()) {
            vm.put("selected", true);
        }
        if (opt.isDisabled()) {
            vm.put("disabled", true);
        }
        return vm;
    }

    private String getJsonFromFile(Resource jsonResource)
            throws RepositoryException, ValueFormatException, PathNotFoundException, IOException {
        String json = null;
        if (!ResourceUtil.isNonExistingResource(jsonResource)) {
            Node cfNode = jsonResource.adaptTo(Node.class);
            InputStream in = cfNode.getProperty("jcr:data").getBinary().getStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            json = sb.toString();
            reader.close();

        }
        return json;
    }

    private class Option {
        String text;
        String value;
        boolean selected;
        boolean disabled;

        public String getText() {
            return text;
        }

        public String getValue() {
            return value;
        }

        public boolean isSelected() {
            return selected;
        }

        public boolean isDisabled() {
            return disabled;
        }
    }

}


XML:
<social
    jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/select"
    fieldLabel="Social Media"
    name="./social">
    <datasource
        jcr:primaryType="nt:unstructured"
        sling:resourceType="/apps/aemtutorials/dropdowns"
        dropdownSelector="fontList"
        options="/content/dam/xxx/font.json"/>

  • 注意Java代码最上边/apps/aemtutorials/dropdowns这个路径要与XML的sling:resourceType相同,实际路径好像没什么意义,只要一样就能将组件与他关联起来。打开组件设置就能触发该servlet
  • XML中的options是记录json文件地址,到时候要在Java中获取该地址去拿json
  • 整体思路应该是先将两者关联-->获取JSON-->JSON格式转来转去-->最后request.setAttribute就能被组件获取到了
  • 看看JSON都转了些什么:
    • Resource jsonResource = resolver.getResource(options.toString()+"/jcr:content");//拿到JSON结点的Resource
    • jsonStr = getJsonFromFile(jsonResource);//Json to String//Resource转String,通过流等方法
    • List<Option> optionList = gson.fromJson(jsonStr, token.getType());//String转List<Option> Option自己定义的
    • ValueMap vm = getOptionValueMap(opt);//Option to ValueMap 将List<Option>迭代,每个Option变成ValueMap
    • optionResourceList.add(new ValueMapResource(resolver, new ResourceMetadata(), "nt:unstructured", vm));//ValueMap变成List<Resource>
    • DataSource ds = new SimpleDataSource(optionResourceList.iterator());//List<Resource>变成DataSource

为什么只要resourceType相同就可以触发呢?

  • 对比:除了resourceType,其实还有paths属性,只要设置对了paths属性,比如/bin/asdf(必须得在bin或apps等这种下面,不然会被forbidden),当你打开网址localhost:4502/bin/asdf就可以触发该servlet了。
  • 所以!只要你打开某个组件中resourceType为xxx的就可以触发该servlet了!
  • 我又思考了一下,上面代码的各种转换应该就是转换为一个个节点,可能是替代了datasource。
posted @ 2021-01-26 09:50  lwxx  阅读(140)  评论(0)    收藏  举报