ofbiz使用之---坑一

使用ofbiz三年了,今天遇见了一个“大坑”

先来说说大坑的前世,由于开发微信小程序用到了上传图片的方法,当然得前后端配合了。后台接口调用的是文件上传的工具类,此工具类在项目中用了有一段时间了,没有发现任何问题。上传文件嘛,相信有经验的程序员都一定很熟悉了,但是同样的接口,pc端调用上传文图没问题,小程序端调用就获取不到图片流。思路如下:
1.小程序api文档没有看清楚?仔细研究小程序api文档,查询各种关于小程序上传图片的资料,无果
2.难道是后台接口不通用吗?查询资料,网上大多是用的spring来写的。但是这跟框架关系不大
3.ofbiz的问题,终于要静下心来,慢慢的解决这个问题。
容小弟喝口水,压压惊,慢慢道来……,分析问题,后台接收不到数据,是没有传递过来吗?带着这个疑问,我用真机测试,控制台log发现,request-headers里面的content-length是有值的,而且每次上传不同图片值的大小不同,这就说明前台图片一定是传递过去了。那么接下来,就是后台的事儿了,以前用spring的时候,记得出现过类似的问题,就是后台拿不到参数,但是前台确实是传过来了,就是因为servlet容器里面,已经解析过一遍了,所以第二次解析的时候,会拿不到数据。抱着这个想法,我看到,web.xml配置里面的

org.apache.ofbiz.webapp.control.ControlServlet

在这个servlet方法中requestHandler.doRequest(request, response, null, userLogin, delegator);,在doRequest方法中有一个checkLoginReturnString = this.runEvent(request, response, checkLoginEvent, null, “security-auth”);
我们继续往下看:

 public String runEvent(HttpServletRequest request, HttpServletResponse response,
            ConfigXMLReader.Event event, ConfigXMLReader.RequestMap requestMap, String trigger) throws EventHandlerException {
        EventHandler eventHandler = eventFactory.getEventHandler(event.type);
        String eventReturn = eventHandler.invoke(event, requestMap, request, response);
        if (Debug.verboseOn() || (Debug.infoOn() && "request".equals(trigger))) Debug.logInfo("Ran Event [" + event.type + ":" + event.path + "#" + event.invoke + "] from [" + trigger + "], result is [" + eventReturn + "]", module);
        return eventReturn;
    }

这个方法是用来判断当前请求的事件类型,具体的事件类型只要分为以下9类:Groovy、Java、Rome、SOAP、Script、Service、ServiceMulti、Simple、XmlRpc,不同的时间类型对应不同的处理器,分别是:GroovyEventHandler、JavaEventHandler、RomeEventHandler、SOAPEventHandler、ScriptEventHandler、ServiceEventHandler、ServiceMultiEventHandler、SimpleEventHandler、XmlRpcEventHandler,关键的点就在这了,通过debug发现,pc调用上传图片接口时,事件类型全部都是java,由于小程序需要验证用户身份token,所以我自定义了一个service,而pc验证用户身份的是LoginWorker,是一个java事件,所以走的是JavaEventHandler,而我这个则用的是ServiceEventHandler,打开ServiceEventHandler才发现了问题的出现的真正原因,下面我把ServiceEventHandler代码贴出来:

boolean isMultiPart = ServletFileUpload.isMultipartContent(request);
        Map<String, Object> multiPartMap = new HashMap<String, Object>();
        if (isMultiPart) {
            // get the http upload configuration
            String maxSizeStr = EntityUtilProperties.getPropertyValue("general", "http.upload.max.size", "-1", dctx.getDelegator());
            long maxUploadSize = -1;
            try {
                maxUploadSize = Long.parseLong(maxSizeStr);
            } catch (NumberFormatException e) {
                Debug.logError(e, "Unable to obtain the max upload size from general.properties; using default -1", module);
                maxUploadSize = -1;
            }
            // get the http size threshold configuration - files bigger than this will be
            // temporarly stored on disk during upload
            String sizeThresholdStr = EntityUtilProperties.getPropertyValue("general", "http.upload.max.sizethreshold", "10240", dctx.getDelegator());
            int sizeThreshold = 10240; // 10K
            try {
                sizeThreshold = Integer.parseInt(sizeThresholdStr);
            } catch (NumberFormatException e) {
                Debug.logError(e, "Unable to obtain the threshold size from general.properties; using default 10K", module);
                sizeThreshold = -1;
            }
            // directory used to temporarily store files that are larger than the configured size threshold
            String tmpUploadRepository = EntityUtilProperties.getPropertyValue("general", "http.upload.tmprepository", "runtime/tmp", dctx.getDelegator());
            String encoding = request.getCharacterEncoding();
            // check for multipart content types which may have uploaded items

            ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory(sizeThreshold, new File(tmpUploadRepository)));

            // create the progress listener and add it to the session
            FileUploadProgressListener listener = new FileUploadProgressListener();
            upload.setProgressListener(listener);
            session.setAttribute("uploadProgressListener", listener);

            if (encoding != null) {
                upload.setHeaderEncoding(encoding);
            }
            upload.setSizeMax(maxUploadSize);

            List<FileItem> uploadedItems = null;
            try {
                uploadedItems = UtilGenerics.<FileItem>checkList(upload.parseRequest(request));
            } catch (FileUploadException e) {
                throw new EventHandlerException("Problems reading uploaded data", e);
            }
            if (uploadedItems != null) {
                for (FileItem item: uploadedItems) {
                    String fieldName = item.getFieldName();
                    //byte[] itemBytes = item.get();
                    /*
                    Debug.logInfo("Item Info [" + fieldName + "] : " + item.getName() + " / " + item.getSize() + " / " +
                            item.getContentType() + " FF: " + item.isFormField(), module);
                    */
                    if (item.isFormField() || item.getName() == null) {
                        if (multiPartMap.containsKey(fieldName)) {
                            Object mapValue = multiPartMap.get(fieldName);
                            if (mapValue instanceof List<?>) {
                                checkList(mapValue, Object.class).add(item.getString());
                            } else if (mapValue instanceof String) {
                                List<String> newList = new LinkedList<String>();
                                newList.add((String) mapValue);
                                newList.add(item.getString());
                                multiPartMap.put(fieldName, newList);
                            } else {
                                Debug.logWarning("Form field found [" + fieldName + "] which was not handled!", module);
                            }
                        } else {
                            if (encoding != null) {
                                try {
                                    multiPartMap.put(fieldName, item.getString(encoding));
                                } catch (java.io.UnsupportedEncodingException uee) {
                                    Debug.logError(uee, "Unsupported Encoding, using deafault", module);
                                    multiPartMap.put(fieldName, item.getString());
                                }
                            } else {
                                multiPartMap.put(fieldName, item.getString());
                            }
                        }
                    } else {
                        String fileName = item.getName();
                        if (fileName.indexOf('\\') > -1 || fileName.indexOf('/') > -1) {
                            // get just the file name IE and other browsers also pass in the local path
                            int lastIndex = fileName.lastIndexOf('\\');
                            if (lastIndex == -1) {
                                lastIndex = fileName.lastIndexOf('/');
                            }
                            if (lastIndex > -1) {
                                fileName = fileName.substring(lastIndex + 1);
                            }
                        }
                        multiPartMap.put(fieldName, ByteBuffer.wrap(item.get()));
                        multiPartMap.put("_" + fieldName + "_size", Long.valueOf(item.getSize()));
                        multiPartMap.put("_" + fieldName + "_fileName", fileName);
                        multiPartMap.put("_" + fieldName + "_contentType", item.getContentType());
                    }
                }
            }
        }

看到这里我想大家都明白了吧,ServiceEventHandler里面已经判断content-type,当是Multipart-formData的时候,就会读取文件流,将文件存在runtime/tmp目录下,作为临时文件,既然request文件流已经读取一遍了,在我们的方法中自然拿不到数据,问题到这里就已经明白了,最后我把验证token的方法改为java事件类型,测试通过~~。

在这里就不得不说一句了,我没搞明白,为什么要在serviceEventHandler里面进行文件的临时读取,不知道原作者的思路,求明白的大神告知小弟一二,小弟在此先行谢过了

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值