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 configurationString 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 uploadString sizeThresholdStr = EntityUtilProperties.getPropertyValue("general", "http.upload.max.sizethreshold", "10240", dctx.getDelegator());int sizeThreshold = 10240; // 10Ktry {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 thresholdString tmpUploadRepository = EntityUtilProperties.getPropertyValue("general", "http.upload.tmprepository", "runtime/tmp", dctx.getDelegator());String encoding = request.getCharacterEncoding();// check for multipart content types which may have uploaded itemsServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory(sizeThreshold, new File(tmpUploadRepository)));// create the progress listener and add it to the sessionFileUploadProgressListener 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 pathint 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里面进行文件的临时读取,不知道原作者的思路,求明白的大神告知小弟一二,小弟在此先行谢过了
ofbiz使用之---坑一相关推荐
- OFBIz gradle构建与运行踩坑
起源与碎碎念 这几天公司要重构ERP,让我负责去研究主流开源ERP系统.本来让我了解的是python的odoo,但是我对py太不熟练,项目代码的依赖本身也很脆弱,最后倒在了一个 Odoo LINE 1 ...
- [CVE-2020-9496]Apache Ofbiz RCE
参考: Apache Ofbiz RCE (CVE-2020-9496) 漏洞分析 CVE-2020-9496 apache ofbiz xml-rpc反序列化漏洞分析 https://www.zer ...
- OFBiz终于起航了
本人菜鸟,菜得不能再菜得那种,在大佬不厌其烦的指点下终于成功了,真的感谢这个网络时代,信息共享的时代 经过这两天的不断反思总结一个要点吧:如果要装软件,去官网,去读redme,根据redme一步不来, ...
- 【golang程序包推荐分享】分享亿点点golang json操作及myJsonMarshal程序包开发的踩坑经历 :)
目录[阅读时间:约5分钟] 一.概述 1.Json的作用 2.Go官方 encoding/json 包 3. golang json的主要操作 二.Json Marshal:将数据编码成json字符串 ...
- java调用clang编译的so_写Java这么久,JDK源码编译过没?编译JDK源码踩坑纪实
好奇害死羊 很多小伙伴们做Java开发,天天写Java代码,肯定离不开Java基础环境:JDK,毕竟我们写好的Java代码也是跑在JVM虚拟机上. 一般来说,我们学Java之前,第一步就是安装JDK环 ...
- flask sqlalchemy踩坑记录
查询 坑1: 查询不存在返回值不全是None 当使用first().one()等函数进行查询时,如果查询不存在,返回值为None 但是如果使用all().paginate()等函数进行查询是,如果返回 ...
- mac git使用与配置踩过的坑
#mac git使用与配置踩过的坑 标题mac配置git ssh密钥 参考链接mac配置git ssh key go get安装失败的解决方法 go get约等于git clone+go instal ...
- 你需要掌握的有关.NET DateTime类型的知识点和坑位 都在这里
引言 DateTime数据类型是一个复杂的问题,复杂到足以让你在编写[将日期从Web服务器返回到浏览器]简单代码时感到困惑. ASP.NET MVC 5和 Web API 2/ASP.NETCo ...
- (转)面试必备技能:JDK动态代理给Spring事务埋下的坑!
一.场景分析 最近做项目遇到了一个很奇怪的问题,大致的业务场景是这样的:我们首先设定两个事务,事务parent和事务child,在Controller里边同时调用这两个方法,示例代码如下: 1.场景A ...
最新文章
- C# 消息处理学习总结
- 个人对北理工2020级硕士研究生张××一篇学术论文涉嫌抄袭的看法
- 作为团队技术负责人,我是这样面试前端的
- linux终端中使用ctrl+c和ctrl+v
- JAVA的字节码技术
- wince版本ffmpeg的编译 第四篇
- Vue 使用 token
- 实数范围内(包含负数)的求模与求余运算异同
- Dubbo管理控制台dubbo-admin搭建
- java 输出helloword
- 自动给神经网络找bug,Google发布TensorFuzz
- LaTex使用Excel实现快速插入表格
- 国内pinterest模式昙花一现 社交电商不该这么玩
- 安卓加密视频播放器使用教程
- 徐思201771010132《面向对象程序设计(java)》第十五周学习总结
- 批量替换 Word 文档前几页
- 【May Be DNK】JSON.parse() and JSON.stringify()的两个实用技巧
- 基于物联网的智慧农业监测系统(前端界面有web端和微信小程序端)
- for和if嵌套使用
- Sci-Hub创始人收到苹果的通知:2年前就把她的账户数据给了FBI
热门文章
- 再谈CPU使用率100%的问题
- linux 麒麟V10 更改磁盘格式ext4-->xfs
- 有一台电脑可以做那些副业
- Java AWT 布局管理器
- 一键搭建微信小程序开发环境 及demo运行(腾讯云上一键搭建node.js服务器环境,PHP,Java,.NET服务类似)
- Python实用案例,Python脚本,Python实现批量加水印
- PDF批量加水印加密丨Acrobat Pro DC
- 高数下|偏导数|高数叔|手写笔记
- Spring Boot 第三篇:理解 spring-boot-starter-parent
- android.mk是在哪儿,Android.mk基础