JavaShop项目总结

@TOCJavaShop项目总结

功能

总结一下,在JavaShop中所做的功能修改。

商铺后台

促销管理

商铺后台的活动时间,在活动开始后,也可以进行更改。

  1. 满减满赠
    com/enation/app/javashop/seller/api/promotion/FullDiscountSellerController.java
	@PutMapping(value = "/{id}")
	@ApiOperation(value	= "修改满优惠活动", response = FullDiscountDO.class)
	@ApiImplicitParams({
		 @ApiImplicitParam(name	= "id",	value =	"主键",	required = true, dataType = "int",	paramType =	"path")
	})
	public	FullDiscountVO edit(@Valid @RequestBody FullDiscountVO fullDiscountVO, @PathVariable Integer id) {

		fullDiscountVO.setFdId(id);
		this.verifyFullDiscountParam(fullDiscountVO,1);
		this.fullDiscountManager.verifyAuth(id);
		this.fullDiscountManager.edit(fullDiscountVO,id);

		return	fullDiscountVO;
	}

在调用修改方法之前,使用this.verifyFullDiscountParam(fullDiscountVO,1);
对满优惠活动的参数信息进行验证;使用this.fullDiscountManager.verifyAuth(id);
来验证操作权限,判断用户是否越权操作。

	@Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {RuntimeException.class, Exception.class, ServiceException.class, NoPermissionException.class})
    public FullDiscountVO edit(FullDiscountVO fullDiscountVO, Integer id) {
        //验证活动时间,同一时间只能有一个活动生效
        this.verifyTime(fullDiscountVO.getStartTime(), fullDiscountVO.getEndTime(), PromotionTypeEnum.FULL_DISCOUNT, id);

        List<PromotionGoodsDTO> goodsDTOList = new ArrayList<>();
        //是否是全部商品参与
        if (fullDiscountVO.getRangeType() == 1) {
            PromotionGoodsDTO goodsDTO = new PromotionGoodsDTO();
            goodsDTO.setGoodsId(-1);
            goodsDTO.setGoodsName("全部商品");
            goodsDTO.setThumbnail("");
            goodsDTOList.add(goodsDTO);
            fullDiscountVO.setGoodsList(goodsDTOList);
        }
        this.verifyRule(fullDiscountVO.getGoodsList());

        // 获取当前登录的店铺ID
        Seller seller = UserContext.getSeller();
        Integer sellerId = seller.getSellerId();
        fullDiscountVO.setSellerId(sellerId);

        FullDiscountDO fullDiscountDO = new FullDiscountDO();
        BeanUtils.copyProperties(fullDiscountVO, fullDiscountDO);

        this.daoSupport.update(fullDiscountDO, id);

        //删除之前的活动与商品的对照关系
        PromotionDetailDTO detailDTO = new PromotionDetailDTO();
        detailDTO.setStartTime(fullDiscountVO.getStartTime());
        detailDTO.setEndTime(fullDiscountVO.getEndTime());
        detailDTO.setActivityId(fullDiscountVO.getFdId());
        detailDTO.setPromotionType(PromotionTypeEnum.FULL_DISCOUNT.name());
        detailDTO.setTitle(fullDiscountVO.getTitle());

        //将活动商品入库
        this.promotionGoodsManager.edit(fullDiscountVO.getGoodsList(), detailDTO);
        cache.put(PromotionCacheKeys.getFullDiscountKey(fullDiscountVO.getFdId()), fullDiscountDO);

        return fullDiscountVO;
    }

this.verifyTime(fullDiscountVO.getStartTime(), fullDiscountVO.getEndTime(), PromotionTypeEnum.FULL_DISCOUNT, id);
这里验证活动时间,同一时间只能有一个活动生效。
this.verifyRule(fullDiscountVO.getGoodsList());
判断商品集合是否为空,检测活动与活动之间的规则冲突。
cache.put(PromotionCacheKeys.getFullDiscountKey(fullDiscountVO.getFdId()), fullDiscountDO);
写入缓存。

  1. 单品立减
    com/enation/app/javashop/seller/api/promotion/MinusSellerController.java
	@PutMapping(value = "/{id}")
	@ApiOperation(value	= "修改单品立减", response = MinusVO.class)
	@ApiImplicitParams({
		 @ApiImplicitParam(name	= "id",	value =	"主键",	required = true, dataType = "int",	paramType =	"path")
	})
	public	MinusVO edit(@Valid @RequestBody MinusVO minus, @PathVariable Integer id) {

		this.minusManager.verifyAuth(id);
		PromotionValid.paramValid(minus.getStartTime(),minus.getEndTime(),minus.getRangeType(),minus.getGoodsList(),1);
		minus.setMinusId(id);
		this.minusManager.edit(minus,id);

		return	minus;
	}

同满减满赠。

  1. 第二件半价
    com/enation/app/javashop/seller/api/promotion/HalfPriceSellerController.java
	@PutMapping(value = "/{id}")
	@ApiOperation(value	= "修改第二件半价", response = HalfPriceDO.class)
	@ApiImplicitParams({
		 @ApiImplicitParam(name	= "id",	value =	"主键",	required = true, dataType = "int",	paramType =	"path")
	})
	public	HalfPriceVO edit(@Valid @RequestBody HalfPriceVO halfPrice, @PathVariable Integer id) {
		PromotionValid.paramValid(halfPrice.getStartTime(),halfPrice.getEndTime(),
				halfPrice.getRangeType(),halfPrice.getGoodsList(),1);

		halfPrice.setHpId(id);
		this.halfPriceManager.verifyAuth(id);
		this.halfPriceManager.edit(halfPrice,id);

		return	halfPrice;
	}

同上。

  1. 拼团管理
    com/enation/app/javashop/seller/api/promotion/PintuanSellerController.java
	@ApiOperation(value = "添加活动")
    @PostMapping
    public Pintuan add(@Valid Pintuan pintuan) {
        return this.pintuanManager.add(pintuan);
    }
    
    @ApiOperation(value = "修改活动")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "主键", required = true, dataType = "int", paramType = "path")
    })
    @PutMapping(value = "/{id}")
    public Pintuan edit(@Valid Pintuan activeDO, @PathVariable Integer id) {
        this.pintuanManager.edit(activeDO, id);
        return activeDO;
    }

先看添加活动,

	@Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Pintuan add(Pintuan pintuan) {

        this.verifyParam(pintuan.getStartTime(), pintuan.getEndTime());
        pintuan.setStatus(PromotionStatusEnum.WAIT.name());
        pintuan.setSellerName(UserContext.getSeller().getSellerName());
        pintuan.setCreateTime(DateUtil.getDateline());
        pintuan.setSellerId(UserContext.getSeller().getSellerId());
        //可操作状态为nothing,代表活动不可以执行任何操作
        pintuan.setOptionStatus(PintuanOptionEnum.NOTHING.name());
        this.tradeDaoSupport.insert(pintuan);
        Integer pintuanId = this.tradeDaoSupport.getLastId("es_pintuan");
        pintuan.setPromotionId(pintuanId);

        //创建活动 启用延时任务
        PintuanChangeMsg pintuanChangeMsg = new PintuanChangeMsg();
        pintuanChangeMsg.setPintuanId(pintuan.getPromotionId());
        pintuanChangeMsg.setOptionType(1);
        timeTrigger.add(TimeExecute.PINTUAN_EXECUTER, pintuanChangeMsg, pintuan.getStartTime(), TRIGGER_PREFIX + pintuan.getPromotionId());
        pintuan.setPromotionId(this.tradeDaoSupport.getLastId("es_pintuan"));
        return pintuan;
    }

this.verifyParam(pintuan.getStartTime(), pintuan.getEndTime());
判断开始时间是否小于结束时间。
timeTrigger.add()
创建活动时,使用延时任务。rabbitmq实现

	@Override
    public void add(String executerName, Object param, Long triggerTime, String uniqueKey) {

        if (StringUtil.isEmpty(uniqueKey)) {
            uniqueKey = StringUtil.getRandStr(10);
        }
        //标识任务需要执行
        cache.put(RabbitmqTriggerUtil.generate(executerName, triggerTime, uniqueKey), 1);

        TimeTriggerMsg timeTriggerMsg = new TimeTriggerMsg(executerName, param, triggerTime, uniqueKey);
        if (logger.isDebugEnabled()) {
            logger.debug("定时执行在【" + DateUtil.toString(triggerTime, "yyyy-MM-dd HH:mm:ss") + "】,消费【" + param.toString() + "】");
        }
        rabbitTemplate.convertAndSend(TimeTriggerConfig.DELAYED_EXCHANGE_XDELAY, TimeTriggerConfig.DELAY_ROUTING_KEY_XDELAY, timeTriggerMsg, message -> {

            Long current = DateUtil.getDateline();
            //如果执行的延时任务应该是在现在日期之前执行的,那么补救一下,要求系统一秒钟后执行
            if (triggerTime < current) {
                message.getMessageProperties().setDelay(1000);
            } else {
                Long time = (triggerTime - current) * 1000 + 5000;
                message.getMessageProperties().setHeader("x-delay", time);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("还有【" + message.getMessageProperties().getExpiration() + "】执行任务");
            }

            return message;
        });
    }

修改活动时,分为活动开始之前修改和活动进行中修改

	@Override
    @Transactional(value = "tradeTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Pintuan edit(Pintuan pintuan, Integer id) {
        //获取拼团活动
        Pintuan oldPintaun = this.getModel(id);
        //校验拼团是否可以被操作

        this.verifyParam(pintuan.getStartTime(), pintuan.getEndTime());
        this.tradeDaoSupport.update(pintuan, id);
        //如果在活动开始之前修改
        if(pintuan.getStatus().equals(PromotionStatusEnum.WAIT.name())) {
            PintuanChangeMsg pintuanChangeMsg = new PintuanChangeMsg();
            pintuanChangeMsg.setPintuanId(pintuan.getPromotionId());
            pintuanChangeMsg.setOptionType(1);
            timeTrigger.edit(TimeExecute.PINTUAN_EXECUTER, pintuanChangeMsg, oldPintaun.getStartTime(), pintuan.getStartTime(), TRIGGER_PREFIX + id);
        } else {
            //活动中,先删除活动的旧关闭任务
            timeTrigger.delete(TimeExecute.PINTUAN_EXECUTER,oldPintaun.getEndTime(),"{TIME_TRIGGER}_"  + id);
            //添加活动的新关闭任务
            PintuanChangeMsg pintuanChangeMsg = new PintuanChangeMsg();
            pintuanChangeMsg.setPintuanId(id);
            pintuanChangeMsg.setOptionType(0);
            timeTrigger.add(TimeExecute.PINTUAN_EXECUTER, pintuanChangeMsg, pintuan.getEndTime(), "{TIME_TRIGGER}_" + id);
        }
        return pintuan;
    }

因为在活动开始之后,会在执行开始活动之后,再向MQ中设置一个关闭活动的延时任务。所以,在活动开始之前修改,只需要修改活动时间以及MQ的开始活动延时任务即可;在活动进行中修改,需要先删除旧的关闭活动的延时任务,再向MQ中设置一个新的关闭活动的延时任务。

	@Override
    public void execute(Object object) {
        PintuanChangeMsg pintuanChangeMsg = (PintuanChangeMsg) object;

        //如果是要开启活动

        if (pintuanChangeMsg.getOptionType() == 1) {
            Pintuan pintuan = pintuanManager.getModel(pintuanChangeMsg.getPintuanId());
            if (PromotionStatusEnum.WAIT.name().equals(pintuan.getStatus()) ||
                    (PromotionStatusEnum.END.name().equals(pintuan.getStatus()) && PintuanOptionEnum.CAN_OPEN.name().equals(pintuan.getOptionStatus()))) {
                pintuanManager.openPromotion(pintuanChangeMsg.getPintuanId());
                //开启活动后,立马设置一个关闭的流程
                pintuanChangeMsg.setOptionType(0);
                timeTrigger.add(TimeExecute.PINTUAN_EXECUTER, pintuanChangeMsg, pintuan.getEndTime(), "{TIME_TRIGGER}_" + pintuan.getPromotionId());
                if (logger.isDebugEnabled()) {
                    this.logger.debug("活动[" + pintuan.getPromotionName() + "]开始,id=[" + pintuan.getPromotionId() + "]");
                }
            }
        } else {
            //拼团活动结束
            Pintuan pintuan = pintuanManager.getModel(pintuanChangeMsg.getPintuanId());
            if (pintuan.getStatus().equals(PromotionStatusEnum.UNDERWAY.name())) {
                pintuanManager.closePromotion(pintuanChangeMsg.getPintuanId());
            }
            if (logger.isDebugEnabled()) {
                this.logger.debug("活动[" + pintuan.getPromotionName() + "]结束,id=[" + pintuan.getPromotionId() + "]");
            }
        }

设置管理

PC端信任登录,登录配置功能
com/enation/app/javashop/seller/api/shopconnect/ShopConnectSettingController.java
点击信任登录,查询列表时,先查询该店铺是否配置过,如果没有,先对配置信息进行添加操作,再返回列表。

会员管理

会员回收站,列表展示、搜索、操作(恢复)。
com/enation/app/javashop/seller/api/member/MemberSellerController.java

	@ApiOperation(value = "查询列表", response = Member.class)
    @GetMapping(value = "/list")
    public Page list(@Valid MemberQueryParam memberQueryParam, @ApiIgnore Integer pageNo,
                     @ApiIgnore Integer pageSize) {
        memberQueryParam.setPageNo(pageNo);
        memberQueryParam.setPageSize(pageSize);
        return this.memberManager.list(memberQueryParam);
    }
    
    @PostMapping(value = "/recovery/{id}")
    @ApiOperation(value = "恢复会员")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "要恢复的会员主键", required = true, dataType = "int", paramType = "path")
    })
    public Member recovery(@PathVariable Integer id) {
        Member member = memberManager.getModel(id);
        if (member == null) {
            throw new ResourceNotFoundException("当前会员不存在");
        }
        if (member.getDisabled().equals(-1)) {
            member.setDisabled(0);
            member.setDisabledTime(null);
            this.memberManager.edit(member, id);
        }
        return member;
    }

前台

小唛店订单

com/enation/app/javashop/buyer/api/trade/OrderBuyerController.java
在列表查询时,修改了SQL语句,关联出订单涉及的商品名称,用于关键字查询。在不改动原有查询条件的基础上,新增了一个关键字字段。
在按标签查询(tag页)时,新增了一个用于小唛店已完成列表查询的case,
XIAO_COMPLETE
原因是小唛店在点击确认收货之后,订单就要显示在已完成列表,而原有易旺铺程序在确认收货之后的订单状态为ROG(已收货)。
还复制了一套商铺后台用到的订单列表查询方法,将原有的已完成(COMPLETE)查询条件做了变更,能查询出COMPLETE和ROG状态的订单,原因是商铺后天列表查询的条件传值即为COMPLETE,不能做出修改。

搜索

商户前台商品搜索和店铺搜索功能,让其只能查询出易旺铺的商品和店铺。

实现商品搜索的前提,在添加商品时,按照店铺id查询其店铺类别,并将店铺类别插入到商品表中。com/enation/app/javashop/seller/api/goods/GoodsSellerController.java

	@ApiOperation(value = "添加商品", response = GoodsDO.class)
	@ApiImplicitParam(name = "goods", value = "商品信息", required = true, dataType = "GoodsDTO", paramType = "body")
	@PostMapping
	public GoodsDO add(@ApiIgnore @Valid @RequestBody GoodsDTO goods) {
		GoodsDO  goodsDO = this.goodsManager.add(goods);
		return goodsDO;
	}
  1. 商品
    com/enation/app/javashop/buyer/api/goods/GoodsSearchBuyerController.java
    商品搜索在构建查询条件的方法中,加入店铺类别的搜索条件,并设置默认值为1(易旺铺)。
		// 店铺类别(易旺铺)
        boolQueryBuilder.must(QueryBuilders.termQuery("shopTypeId", "1"));

在商品索引实现的实现类中,找到封装成内存需要格式数据的方法,在索引中加入店铺类别,就可以在查询时,实现只查询易旺铺商品。
2. 店铺
com/enation/app/javashop/buyer/api/shop/ShopBuyerController.java

	@ApiOperation(value = "查询店铺列表", response = ShopListVO.class)
    @GetMapping("/list")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "page_no", value = "页码", required = true, dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "page_size", value = "分页数", required = true, dataType = "int", paramType = "query"),
            @ApiImplicitParam(name = "name", value = "店铺名称", required = false, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "order", value = "按好评率排序", required = false, dataType = "String", paramType = "query")
    })
    public Page list(@ApiIgnore @NotNull(message = "页码不能为空") Integer pageNo, @ApiIgnore @NotNull(message = "每页数量不能为空") Integer pageSize, String name, String order) {
        ShopParamsVO shopParams = new ShopParamsVO();
        shopParams.setPageNo(pageNo);
        shopParams.setPageSize(pageSize);
        shopParams.setShopName(name);
        shopParams.setOrder(order);
        return shopManager.listShopBasicInfo(shopParams);
    }

在店铺列表查询的SQL语句中,加入店铺类别字段并默认值为1(易旺铺),即可实现功能。

平台

店铺菜单权限

完善平台后台的店铺菜单权限功能,实现店铺菜单权限的添加修改和删除功能。
com/enation/app/javashop/manager/api/shop/ShopMenuAuthController.java
店铺菜单权限,实现的功能是对一类店铺进行菜单权限的配置,关联到店铺类别表。所以,在添加功能时,先对店铺类别进行了添加操作,然后再将菜单权限信息入库。

	@Override
    public ShopMenuAuthVO add(ShopMenuAuthVO shopMenuAuthVO) {

        //添加店铺类别
        ShopType shopType = new ShopType();
        shopType.setTypeName(shopMenuAuthVO.getShopTypeName());
        this.memberDaoSupport.insert(shopType);
        //角色信息入库
        ShopMenuAuthDO shopMenuAuthDO = new ShopMenuAuthDO();
        shopMenuAuthDO.setAuthDescribe(shopMenuAuthVO.getShopTypeName() + "菜单");
        shopMenuAuthDO.setShopTypeId(memberDaoSupport.getLastId("es_shop_type"));
        shopMenuAuthDO.setAuthIds(JsonUtil.objectToJson(queryShopMenuList()));
        this.memberDaoSupport.insert(shopMenuAuthDO);
        shopMenuAuthVO.setId(memberDaoSupport.getLastId("es_shop_menu_auth"));
        return shopMenuAuthVO;
    }

其中用到了 queryShopMenuList() 方法对所有的店铺菜单信息进行了查询。这么做的原因是,如果不在添加时,将所有店铺菜单信息转换成Json串格式插入到数据库中,那么就不能进行修改操作,前台会出现异常。

	/**
     * 查询店铺菜单信息集合
     *
     * @param
     * @return List<ShopMenus>
     */
    private List<ShopMenus> queryShopMenuList() {
        String sql = "SELECT id,parent_id,title,identifier,auth_regular,delete_flag,path,grade FROM es_shop_menu WHERE delete_flag = 0";
        //店铺菜单信息集合
        List<ShopMenu> rootShopMenuList = this.memberDaoSupport.queryForList(sql, ShopMenu.class);
        //要返回的结果店铺菜单信息集合
        List<ShopMenus> shopMenusList = new ArrayList<>();
        //先找到所有的一级菜单
        if(rootShopMenuList != null && rootShopMenuList.size() > 0) {
            //遍历所有菜单集合
            for(int i = 0 ; i < rootShopMenuList.size() ; i++) {
                //一级菜单没有父id
                if(rootShopMenuList.get(i).getParentId() == 0) {
                    ShopMenus shopMenus = new ShopMenus();
                    shopMenus.setId(rootShopMenuList.get(i).getId());
                    shopMenus.setTitle(rootShopMenuList.get(i).getTitle());
                    shopMenus.setIdentifier(rootShopMenuList.get(i).getIdentifier());
                    shopMenus.setChecked(false);
                    shopMenus.setAuthRegular(rootShopMenuList.get(i).getAuthRegular());
                    //将菜单加入集合
                    shopMenusList.add(shopMenus);
                }
            }
            //为一级菜单设置子菜单
            if(shopMenusList != null && shopMenusList.size() > 0) {
                for(ShopMenus shopMenus : shopMenusList) {
                    shopMenus.setChildren(getMenuChild(shopMenus.getId(), rootShopMenuList));
                }
            }
        }
        return shopMenusList;
    }

    /**
     * 递归查找子菜单
     *
     * @param menuId,rootShopMenuList
     * @return List<ShopMenus>
     */
    private List<ShopMenus> getMenuChild(Integer menuId, List<ShopMenu> rootShopMenuList) {
        //子菜单
        List<ShopMenus> childList = new ArrayList<ShopMenus>();
        for(ShopMenu shopMenu : rootShopMenuList) {
            if(shopMenu.getParentId() == menuId) {
                ShopMenus shopMenus = new ShopMenus();
                shopMenus.setId(shopMenu.getId());
                shopMenus.setTitle(shopMenu.getTitle());
                shopMenus.setIdentifier(shopMenu.getIdentifier());
                shopMenus.setChecked(false);
                shopMenus.setAuthRegular(shopMenu.getAuthRegular());
                //将子菜单加入集合
                childList.add(shopMenus);
            }
        }
        // 把子菜单的子菜单再循环一遍
        if(childList.size() > 0) {
            for(ShopMenus shopMenus : childList) {
                //递归
                shopMenus.setChildren(getMenuChild(shopMenus.getId(), rootShopMenuList));
            }
        }
        //递归退出条件
        if(childList.size() == 0) {
            return null;
        }
        return childList;
    }
Javashop开发规范V2.2 版本 说明 提交人 V1.0 初稿 定义了包名、异常、事务、和路径的规范 王峰 V2.0 1. 重新整理了命名规范 2. 增加常用命词对照表 王峰 V2.1 1.增加数据库操作的说明 2.增加常用方法介绍 王峰 V2.2 增加关于数据导入导出的说明 王峰 V2.3 增加校验使用说明(5.3章节) 王峰 1 命名规范 1.1 包命 1. 小写字母 2. 以com.enation.javashop开头 3. 组件以com.enation.compoent开头 1.2 类名 一、 action 以Action结尾,如:UserAction 二、 业务类 1.接口: 以I开头,以Manager结尾,如:IUserManager 2.实现类 以Manager结尾,如:UserManager 三、 组件类 以Component结尾,如:ShopEmailComponent 四、 挂件类 以Widget结尾,如:MemberAddressWidget 五、 插件类 以Plugin结尾,如:SendRegMailPlugin 1.3 变量/属性命名规则 1. 全部小写 2. 可用下划线连接 如:username、 userid 1.4 方法命名 1.4.1 Action类 add 到添加页 edit 到修改页 saveAdd 保存添加 saveEdit 保存修改 delete 删除 list 列表 1.4.2 业务类 add 添加 edit 修改 delete 删除 list 列表 get 读取详细 2 数据库开发规范 2.1 数据操作支持类 一、 业务类数据库调用 1.继承于BaseSupport 2.在spring文件中声明parent为baseSupport <bean id="xxxManagerImpl" class="xxx.xxx.xxx.XxxxManager" parent="baseSupport"/> 3.通过this.baseDaoSupport操作数据库 实际使用的是:com.enation.eop.sdk.database.BaseJdbcDaoSupport 此种操作示例: com.enation.javashop.core.service.impl.BrandManager 注意事项:见【BaseDaoSupport的意义和存在的问题】 二、 直接声明baseDaoSupport操作数据库 在一些挂件类中或某些特殊情况,可以直接需要直接声明baseDaoSupport 此种操作示例: com.enation.javashop.core.service.impl.batchimport.GoodsSpecImporter 注意事项:见【BaseDaoSupport的意义和存在的问题】 2.2 BaseDaoSupport的意义存在的问题 BaseDaoSupport对JdbcDaoSupport进行包装,通过 baseDBRouter 获取表名, 为什么要通过 baseDBRouter 来获取表名呢?Eop机制是支持SAAS(多租户)模式运行的,在SAAS会为每个用户提供如:es_goods_<userid>_<siteid>这样的表。 为了保证在单机版和SAAS模式中都运行正常,BaseDaoSupport将过滤sql中的相应表名。 但目前还只能支持简单的单表select、insert、update,对于多表的联合查询或更新不能支持。 在这种情况下,就需要通过 daoSupport(com.enation.framework.database.impl.JdbcDaoSupport)来操作,daoSupport不对sql进行任何更改,这时为了保证兼容saas模式兼容性,就要使用BaseSupport.getTableName(String tablename)方法 或baseDBRouter.getTableName(String tablename);来保证表名的正确。 (够混乱?真心希望出现一位大侠拯救这个状况,使basedaosupport可以处理所有情况的sql) 2.3 实体Bean和数据库表对照 Javahop数据库操作支持,将对象直接保存或修改,如: this.baseDaoSupport.insert("brand", brand); this.baseDaoSupport.update("brand", brand, "brand_id=" + brand.getBrand_id()); 规则为:实体中的属性名和数据库表的字段名相同,如: 对应的数据库字段: 2.4 注解的使用 2.4.1 @NotDbField 在某个实体Bean中,我们可能会有一些属性不对应数据库字段,这时我们需要在相应的 Geter方法中加上@NotDbField注解,以便使数据库机制知道这个字段不转为sql语句,如: private File file; @NotDbField public File getFile() { return file; } 2.4.2 @PrimaryKeyField 在实合格bean和数据库对照过程中,数据库机制需要识别主键,所以需要我们在主键的对应属性的Geter方法中加上@PrimaryKeyFiled注解,如: private Integer brand_id @PrimaryKeyField public Integer getBrand_id() { return brand_id; } 3 数据导入 3.1 导入接口 DBSolutionFactory.dbImport("file:com/enation/javashop/component/coupon/add.xml","es_"); 3.2 数据Xml文件说明 3.2.1 创建表 <action> <command>create</command> <table>tablename</table> <field> <name>id</name> <type>int</type> <size>8</size> <option>11</option> </field> <field> <name>name</name> <type>varchar</type> <size>255</size> <option>00</option> </field> </action> 3.2.2 删除表 <action> <command>drop</command> <table>tablename</table> </action> 3.2.3 添加、删除列 <action> <command>alter</command> <table>goods</table> <field type="add"> <name>isgroupbuy</name> <type>int</type> <size>1</size> <default>0</default> </field> <field type="drop"> <name>isgroup</name> </field> </action> 3.2.4 创建索引 <action> <command>index</command> <table>goods</table> <field > <name>goodsid</name> </field> </action> 3.2.5 删除索引 <action> <command>unindex</command> <table>goods</table> <field > <name>goodsid</name> </field> </action> 3.2.6 插入数据 <action> <command>insert</command> <table>es_adcolumn</table> <fields>acid,cname,width,height,atype,disabled</fields> <values>5,'列表页上部横幅','972px','67px',0,'false'</values> </action> 3.2.7 删除数据 暂未支持 3.2.8 更新数据 暂未支持 3.3 数据类型对照表 xml Mysql Oracle SqlServer int int NUMBER smallint int(1) smallint(1) NUMBER(2) int memo text CLOB text datetime datetime TIMESTAMP datetime long bigint NUMBER bigint decimal decimal NUMBER(20,2) decimal 4 数据导出 String[] tables = new String[1]; tables[0] = "es_auth_action"; DBSolutionFactory.dbExport(tables, false, "") 5 常用方法介绍 5.1 上下文获取 参见: http://www.javamall.com.cn/developer_help/index.php/常用方法 5.2 地区联动下拉框 1.如果是在jsp 中: <html:regionselect></html:regionselect> 2.如果是在Freemarker的html中: <#assign RegionSelect= "com.enation.app.base.component.widget.regions.RegionSelectDirective"?new()> <@RegionSelect /> 以上两种方式均支持以下参数: province_id:省id city_id:市id region_id:区id 如果指定上述参数,则默认选中 5.3 客户端校验 EOP自动为应用提供表单校验功能,通过指定form样式名和指定表单项特定属性的方式来完成。 5.3.1 示例 代码示例 [removed] function checkUserName(val){ if(val=='kingapex' ) return true; else return "用户名已存在"; } $.Validator.options={lang:{isrequired:'此项不能为空!'}}; [removed] <form class="validate"> 必须:<input type="text" name="test1" isrequired="true"> <br/> 整型:<input type="text" name="test2" isrequired="true" dataType="int"> <br/> 浮点型:<input type="text" name="test3" dataType="float"> <br/> 邮件:<input type="text" name="test4" isrequired="true" dataType="email"> <br/> 日期:<input type="text" name="test5" isrequired="true" dataType="date"> <br/> 电话号码:<input type="text" name="test6" isrequired="true" dataType="tel_num"> <br/> 手机:<input type="text" name="test7" isrequired="true" dataType="mobile"> <br/> 邮政编码:<input type="text" name="test8" isrequired="true" dataType="post_code"> <br/> 网址:<input type="text" name="test9" isrequired="true" dataType="url"> <br/> 自定义函数:<input type="text" name="test10" isrequired="true" fun="checkUserName"> <br/> <input type="submit" value="确定" /> </form> 5.3.2 参数说明: 5.3.2.1 isrequired 为true则为必填项,不指定或指为false则为非必填项。 5.3.2.2 dateType 指定校验特殊类型,支持的类型见下表: 类型 说明 int 整数 float 浮点数 email 邮件格式 date 日期格式 tel_num 电话格式 mobile 手机格式 post_code 邮编 url 网址 5.3.2.3 fun 自定义校验函数,返回真则通过校验,返回假或字串则校验失败,返回的字串会出现在失败提示框中。 5.3.2.4 动态绑定校验函数 通过 setValidator实现 $("#region_id").setValidator(function(){ var value = $("#region_id").val(); if( value=="" || value=="0" ) return "地区信息不完整"; else return true; }); 5.3.2.5 提示器 提示器用于显示校验的结果,如果不指定默认会在校验的控件后面创建一个span做为提示器。 可以通过两种方式指定提示器: 一、在控件中声明tiper属性: <input type="text" name="username" tiper="#name_tiper" /> 注:tiper指定的是jquery的一个选择器表达式。 二、动态指定: $("#region_id").setTiper($("#name_tiper")); 注:此时指定的是jquery对象,而不是一个表达式 5.3.2.6 手动调用: $("#siteForm").checkall(); 6 常用字典对照表 6.1 常用值 名称 值 说明 返回结果 0:失败 1:成功 适用于: 1. 客户端json返回值 2. 服务器端方法返回值 3. 数据库是否的标识值 性别 0:女 1:男 6.2 常用名称 名称 英文 商品 goods 货品 product 规格 spec 订单 order 会员 member 积分 point 购物车 cart 结算 checkout 订单 order 品牌 brand 分类 cat 优惠劵 coupon 支付 payment 团购 groupbuy 虚拟 virtual 发票 receipt 属性 prop 参数 param 标签 tag 地区 region 7 异常 1. 提供统一的异常处理机制 2. 底层级别的类不处理异常,只管向上抛出异常,且统一抛出RuntimeExcepton 8 事务处理 1. 数据库统一使用Srping AOP事务 2. 采用注解方式: 在接口处: @Transactional(propagation = Propagation.isrequired) 9 路径的规范 返回的路径变量最后不带 ‘/’ 如:String path =”user/1”; 使用者: path = path+”/”+myVar; 10 样式/HTML规范 10.1 前台分页 <div class="page"><span class="info">共41条记录</span> <span class="info">1/3</span> <ul><li><a class="selected">1</a></li> <li><a href="search-cat-4-page-2.html" class="unselected">2</a></li> <li><a href="search-cat-4-page-3.html" class="unselected">3</a></li> <li><a href="search-cat-4-page-2.html" class="unselected">>></a></li> <li><a href="search-cat-4-page-3.html" class="unselected">>|</a></li> </ul></div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值