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

本文围绕Webx、Velocity和MyBatis展开。介绍了在Webx的Velocity中获取URL参数、防止CSRF攻击的方法;阐述MyBatis中mapper层association标签的使用及对象关联;还提及批量查询接口性能优化,以及xml文件中CDATA部分的作用。

一、总结

在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等。

附录:

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

基础架构事业群业务。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值