热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

velocity变量获取_记录一次bug解决过程:velocity中获取url中的参数

一、总结在Webx的Velocity中获取url中参数:$rundata.getRequest().getParameter(userId)在Webx项目中ÿ

一、总结

在Webx的Velocity中获取url中参数:$rundata.getRequest().getParameter('userId')

在Webx项目中,防止CSRF攻击(Cross-site request forgery,跨站请求伪造),在form表单提交中要加入$!csrfToken.ajaxUniqueToken

在MyBatis的mapper层,使用标签association实现对象的关联,一个bean配多个association标签。

二、Bug描述:Velocity从URL中获取parameter参数

在项目IDCM中,使用webx容器进行项目的开发。前端的模板引擎采用了velocity,在项目中,当从列表页跳到详情页的时候,通常我们的screen层是采用如下方式进行展现的:

public class EditRules extendsBaseScreen {

@AutowiredprivateAutoAssignSupplierBo autoAssignSupplierBo;

@AutowiredprivateSupplierBo supplierBo;

@AutowiredprivateAddressBo addressBo;

@AutowiredprivateSiteBo siteBo;public void execute(@Param("id")

String id, Context context)throwsException {

QueryAssignRulesrDo query= newQueryAssignRulesrDo();if(StringUtils.isBlank(id)) {throw new ServiceException("id is empty ");

}

query.setRuleId(Long.parseLong(id));

BoResultDTO> result =autoAssignSupplierBo.selectByQuery(query);

List list =result.getData();if(CollectionUtils.isNotEmpty(list)) {//当前规则的详情

if (StringUtils.isNotBlank(list.get(0).getType())) {

list.get(0).setTypeVal(list.get(0).getType());

list.get(0).setType(WorkOrderCst.RelocationType.getNameByStrValue(list.get(0).getType()));

}//如果有数量信息需要展示

if (list.get(0).getRuleContent().contains("数量")) {

String[] numDes= list.get(0).getRuleContent().split(" ");for(String str : numDes) {if (str.contains("数量")) {

String[] sz= str.split(":");if (2 ==sz.length) {

list.get(0).setAssetNum(sz[1]);

}

}

}

}

context.put("ruleInfos", JSON.toJSONString(list.get(0)));//补全控件信息

Map map = fullInfo(list.get(0).getRuleJsonVal());if (list.get(0).getRuleContent().contains("数量")) {

map.put("assetNum", list.get(0).getAssetNum());

}

context.put("ruleDes", JSONUtils.toJSONString(map));

}//初始化类型信息

Map RelocationTypeList =WorkOrderCst.RelocationType.getRelocationTypeList();

context.put("RelocationTypeList", RelocationTypeList);//物流供应商信息

context.put("logisticsSps", supplierBo.queryAllByType(WorkOrderCst.SpType.logistics.name()));//传入设备类型

this.setorderDeviceType(context);

}

}

上图代码是自动分配物流供应商从列表页跳转到详情页的时候,需要显示调用screen层的跟*.vm同名的*.java方法,通过传入参数id,即选择了指定行,后台会将查询到的数据封装到对象中,在vm中可以直接使用,而不用再走ajax请求,提升了系统的反映速度。其中在BaseScreen.java中负责公共日志的输出,当前权限的获取,以及一些公共属性的动态获取。但是,有一些业务场景中,我们在进行跳转的时候,只需要知道跳转过来的当前id,并不需要后端来加载数据。这时候,如果能从vm中直接获取跳转过来的url的parameter参数,那么就可以省去跟*.vm同名的*.java中的execute方法。

//唯一正确的用法:

//以下几种用法都无法获取到参数的值

$!request.parameter.userId

$!request.paarmater.getParameter('userId')

此外,Velocity更多使用细节参考英文官方文档或

三、Bug描述:$!csrfToken.hiddenField

CSRF(跨站请求伪造),它通过伪装来自受信任用户的请求来利用受信任的网站。在IDCM项目中,在*.vm页面会有大量的表单提交,在表单提交的时候,为了防止跨站请求伪造,要在form标签之后紧跟$!csrfToken.ajaxUniqueToken。

$!csrfToken.hiddenField

上述代码中,在VM文件的form表单中添加了token。该表单请求极有可能涉及数据增删改,需要防范CSRF,请确认使用POST请求,增加token参数,并在服务端校验token。

三、Bug描述:MyBatis中mapper层的association标签使用

API接口调用,web层/openapi/rack代码如下,RpcResult做为接口查询返回的对象,包括Data、info、Success,所以该层合理的代码应该包含try catch,正确的逻辑打印正确的信息。一旦接口调用错误,要返回合适的信息。

//根据房间和机柜名称,批量查询机柜信息 @ResourceMapping("batchQueryRackByRoomNameAndRackName")

public RpcResult batchQueryRackByRoomNameAndRackName(@RequestParam(name = "queryParam")

String queryParam) {

RpcResult rpcResult = new RpcResult();try{

@SuppressWarnings("unchecked")

List list = (List) JsonToBeanUtil.JsonToJavaBean(queryParam, RackAndRoom.class);

List rackList = new ArrayList();if(CollectionUtils.isNotEmpty(list)) {for(RackAndRoom rackAndRoom : list) {

checkParameter(rackAndRoom);

Rack rack=rackBo.batchQueryRackByRoomNameAndRackName(rackAndRoom.getRackName(), rackAndRoom.getRoomName());

rackList.add(rack);

}

rpcResult.setData(rackList);

rpcResult.setInfo("查询成功!");

rpcResult.setSuccess(true);

}

}catch(Exception e) {

logger.error(" batchQueryRackByRoomNameAndRackName error:" +e.getMessage(), e);

rpcResult.setSuccess(false);

rpcResult.setInfo("查询失败,具体异常信息为:" +e.getMessage());

}returnrpcResult;

}

上述的代码结构在接口查询中,利用了分类的思想,针对接口查询成功和失败,分别对info、success、data进行赋值。并且如果失败,会有日志记录。异常的捕获在RPC层(addError)、Bo层(事务回滚)、OpenAPI层要区别对待。对于RPC中的错误,因为它是通过浏览器跟用户交互的,所以一般会将错误添加到Error对象中,将错误信息反馈给浏览器端的用户,使得用户可以修改自己的操作,达到预期的效果。

/*** 修改排序*/@ResourceMapping("updateOrderIng")public RpcResultupdateOrderIng(@RequestParams

AssignRulesVo assignRulesVo, @RequestParam(name= "type")

String type, ErrorContext error) {

RpcResult result = new RpcResult();

result.setSuccess(true);try{if (null == assignRulesVo || null == assignRulesVo.getOrdering() ||StringUtils.isBlank(type)) {throw new SerialException("缺少排序信息和规则信息,无法修改");

}

autoAssignSupplierBo.updateOrderIng(assignRulesVo, type);

result.setInfo("修改排序成功");

result.setData(true);

}catch(Exception e) {

result.setSuccess(false);

logger.error("updateOrderIng err : ", e.getMessage(), e);

addError(error, ErrorCode.Sys_Error.getCode(), e.getMessage(), result);

}returnresult;

}

对比可以看到RPC中,通常会传入Error对象,使用addError方法,将错误信息反馈到前端。接着讲openapi中的查询接口,它通过调用bo层、boImpl层、Ext层的rackMapperExt.batchQueryRackByRoomNameAndRackName(map);来查询。

select

FROM

idc_rack temp_rack

INNER JOIN idc_room temp_room ON temp_rack.room_id = temp_room.room_id

INNER JOIN idc_site temp_site ON temp_room.site_id = temp_site.site_id

WHERE

temp_rack.is_deleted = 'n'

AND temp_room.is_deleted = 'n'

AND temp_site.is_deleted = 'n'

AND temp_rack.rack_name = #{rackName}

AND temp_room.room_name = #{roomName}

在代码中,查询到的参数采用了标签,将要查询的room、rack、site等信息捞出来,最后映射到BaseResultMap_Ext中,如下:

通过标签实现了对象映射的时候的一对多的关联,上述resultMap使用extends="BaseResultMap"扩展了对象映射,其中BaseResultMap来自于Mybatis自动生成的mapper中的映射关系。

四、批量查询接口性能优化

ext层:

@Resourcepublic interface RackMapperExt extendsRackMapper {

List batchQueryRackByRoomNameAndRackName(Listlist);

}

mapper层:

select

FROM

idc_rack temp_rack

INNER JOIN idc_room temp_room ON temp_rack.room_id=temp_room.room_id

INNER JOIN idc_site temp_site ON temp_room.site_id=temp_site.site_id

WHERE

temp_rack.is_deleted= 'n'AND temp_room.is_deleted= 'n'AND temp_site.is_deleted= 'n'AND(temp_rack.rack_name= #{item.rackName} AND temp_room.room_name =#{item.roomName})

五、MyBatis中的使用

在xml文件中,处于CDATA部分中的所有内容都会被解析器忽略,避免由于>&等sql字符影响xml文档结构,segmentfault问题:

六、待补充:阿里巴巴缓存使用bacardi、tail等。

附录:

阿里巴巴-基础架构事业群业务,项目路径:

基础架构事业群业务。



推荐阅读
  • publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ... [详细]
  • MVC框架下使用DataGrid实现时间筛选与枚举填充
    本文介绍如何在ASP.NET MVC项目中利用DataGrid组件增强搜索功能,具体包括使用jQuery UI的DatePicker插件添加时间筛选条件,并通过枚举数据填充下拉列表。 ... [详细]
  • 本文详细探讨了 Java 中 com.codahale.metrics.servlets.AdminServlet.() 方法的实现与应用,并提供了多个实际项目中的代码示例,帮助开发者更好地理解和使用这一方法。 ... [详细]
  • 本文介绍了在解决Hive表中复杂数据结构平铺化问题后,如何通过创建视图来准确计算广告日志的曝光PV,特别是针对用户对应多个标签的情况。同时,详细探讨了UDF的使用方法及其在实际项目中的应用。 ... [详细]
  • 本文探讨了如何通过优化 DOM 操作来提升 JavaScript 的性能,包括使用 `createElement` 函数、动画元素、理解重绘事件及处理鼠标滚动事件等关键主题。 ... [详细]
  • 本文详细介绍了JQuery Mobile框架中特有的事件和方法,帮助开发者更好地理解和应用这些特性,提升移动Web开发的效率。 ... [详细]
  • Bootstrap Paginator 分页插件详解与应用
    本文深入探讨了Bootstrap Paginator这款流行的JavaScript分页插件,提供了详细的使用指南和示例代码,旨在帮助开发者更好地理解和利用该工具进行高效的数据展示。 ... [详细]
  • 拖拉切割直线 ... [详细]
  • VS Code 中 .vscode 文件夹配置详解
    本文介绍了 VS Code 中 .vscode 文件夹下的配置文件及其作用,包括常用的预定义变量和三个关键配置文件:launch.json、tasks.json 和 c_cpp_properties.json。 ... [详细]
  • 本文详细介绍如何在Spring Boot项目中集成和使用JPA,涵盖JPA的基本概念、Spring Data JPA的功能以及具体的操作步骤,帮助开发者快速掌握这一强大的持久化技术。 ... [详细]
  • 本文旨在探讨如何撰写高效且全面的工作总结,特别是针对数据库管理、Java编程及Spring框架的学习与应用。文章通过实例分析,帮助读者掌握工作总结的写作技巧,提高个人工作汇报的质量。 ... [详细]
  • 本文介绍了多种Eclipse插件,包括XML Schema Infoset Model (XSD)、Graphical Editing Framework (GEF)、Eclipse Modeling Framework (EMF)等,涵盖了从Web开发到图形界面编辑的多个方面。 ... [详细]
  • BeautifulSoup4 是一个功能强大的HTML和XML解析库,它能够帮助开发者轻松地从网页中提取信息。本文将介绍BeautifulSoup4的基本功能、安装方法、与其他解析工具的对比以及简单的使用示例。 ... [详细]
  • Kubernetes Services详解
    本文深入探讨了Kubernetes中的服务(Services)概念,解释了如何通过Services实现Pods之间的稳定通信,以及如何管理没有选择器的服务。 ... [详细]
  • 本文介绍了如何正确配置Ajax POST请求,以确保前端发送的数据能够被后端正确解析。重点在于前端JSON对象的键名需要与后端实体类的字段名严格匹配。 ... [详细]
author-avatar
上帝的宝贝1
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有