美文网首页
03:[后台框架] 自写框架, 简单快速开发后台小示例, 已上传

03:[后台框架] 自写框架, 简单快速开发后台小示例, 已上传

作者: M_SRC | 来源:发表于2019-07-25 10:46 被阅读0次

项目已部署好的直接更新项目就可以运行了.
没部署好的可参照序章
序:自己写的后台框架开源给大家,仅供学习,不喜勿喷.
Git地址:https://github.com/huhuanan/m

该示例已实现功能:

  1. 首页自定义页面;
  2. 三张表的定义; (启动时会自动创建)
  3. 三个菜单, 以及简单功能;
  4. 其中有个一菜单增加了echart简单图表和excel导出功能

代码讲解


1. 配置文件

  • config/mconfig.properties 配置action和model的包
#数据库模型包, 多个用逗号分开(,)
model_pack=manage.model,goods.model
#action包, 多个用逗号分开(,)   继承m.common.action 系统Action
action_pack=manage.action,test.action,goods.action

配置后, 系统初始化时会识别对应的action和model

  • config/module.xml 配置后台菜单
    <module oid="B" sort="2" name="商品管理" icoStyle="&#xe6ae;" isPublic="N">
        <menu oid="B01" sort="201" name="商品首页" icoStyle="&#xe70b;" description="" isPublic="N">
            <menu oid="B0101" sort="20101" name="首页" urlPath="page/goods/home/index.html" description="" isPublic="N"></menu>
        </menu>
        <menu oid="B11" sort="211" name="商品管理" icoStyle="&#xe70b;" description="" isPublic="N">
            <menu oid="B1101" sort="21101" name="商品信息" urlPath="action/goodsGoodsInfo/toList?method=goodsInfoData" description="" isPublic="N"></menu>
            <menu oid="B1102" sort="21102" name="商品库存" urlPath="action/goodsGoodsStock/toList?method=goodsStockData" description="" isPublic="N"></menu>
        </menu>
        <menu oid="B12" sort="212" name="商品销售" icoStyle="&#xe70b;" description="" isPublic="N">
            <menu oid="B1201" sort="21201" name="商品订单" urlPath="action/goodsGoodsOrder/toList?method=goodsOrderData" description="" isPublic="N"></menu>
        </menu>
    </module>

每次重启, 菜单都会全部删除并根据config/mconfig.properties配置文件重新插入数据库, 如果是已经运行的项目, oid不要变动, 层级也不能变动, 不然需要重新给用户组授权.
sort排序, name菜单名, isPublic N代表非公共菜单
icoStyle图标 在/web/resources/default/iconfont-admin/demo_unicode.html可以选择图标,

2. action类

商品信息的action类, 因为商品有个状态属性, 继承StatusAction父类,(继承了ManageAction)

@ActionMeta(name="goodsGoodsInfo")
public class GoodsInfoAction extends StatusAction {
  ....
}

商品订单的Action类, 继承ManageAction类

@ActionMeta(name="goodsGoodsOrder")
public class GoodsOrderAction extends ManageAction {
  ....
}

还有个商品库存的Action, 和商品订单同样继承了ManageAction类

1. ManageAction父类: 实现了后台的编辑,列表,图表和导出功能.

  • 列表实现
    /**
     * 查询列表
     * @return
     */
    @ActionTableMeta(dataUrl = "action/goodsGoodsInfo/goodsInfoData",
            modelClass="goods.model.GoodsInfo",tableHeight=500,
            searchField="name",searchHint="请输入名称",
        cols = { 
            @ActionTableColMeta(field = "oid", title = "",type=TableColType.INDEX),
            @ActionTableColMeta(field = "status", title = "状态",type=TableColType.STATUS,power="goods_manager_power",dictionaryType="status",align="center"),
            @ActionTableColMeta(field = "name", title = "名称", width=130,sort=true,initSort=TableColSort.DESC),
            @ActionTableColMeta(field = "price", title = "单价", width=130,sort=true,numberFormat="0.00",align="right"),
            @ActionTableColMeta(field = "stockNum", title = "库存", width=130,sort=true,numberFormat="#,##0",align="right",countType=TableCountType.SUM),
            @ActionTableColMeta(field = "saleNum", title = "销量", width=130,sort=true,numberFormat="#,##0",align="right",countType=TableCountType.SUM),
            @ActionTableColMeta(field = "oid",title="操作",width=120,align="center",buttons={
                @ButtonMeta(title="修改", event = ButtonEvent.MODAL,modalWidth=700, url = "action/goodsGoodsInfo/toEdit",
                    params={@ParamMeta(name = "model.oid", field="oid")},success=SuccessMethod.REFRESH,style=ButtonStyle.NORMAL,
                    power="goods_manager_power"
                ),
            })
        },
        querys = {
            @QueryMeta(field = "name", name = "名称", type = QueryType.TEXT, hint="请输入名称", likeMode=true),
            @QueryMeta(field = "price", name = "单价", type = QueryType.DOUBLE_RANGE)
        },
        buttons = {
            @ButtonMeta(title="新增", event = ButtonEvent.MODAL,modalWidth=700,  url = "action/goodsGoodsInfo/toEdit", 
                success=SuccessMethod.REFRESH,style=ButtonStyle.NORMAL,
                power="goods_manager_power"
            )
        }
    )
    public JSONMessage goodsInfoData(){
        return getListDataResult(null);
    }

@ActionTableMeta注解
dataUrl:就是这个方法的访问地址,
modelClass:查询列表基类, 基于这个对象开始查询
cols: 列,@ActionTableColMeta注解数组

@ActionTableColMeta注解
field:列对应数据库的字段

属性比较多, 可以查看注释源码里面描述, 这里就不一一讲解了.
以上代码实现了返回列表的数据部分, 列表是从菜单直接进来的, 可以查看菜单的链接

<menu oid="B1101" sort="21101" name="商品信息" urlPath="action/goodsGoodsInfo/toList?method=goodsInfoData" description="" isPublic="N"></menu>

action/goodsGoodsInfo/toList?method=方法名
toList 是继承了ManageAction的方法

  • 实现编辑
    @ActionFormMeta(title="商品信息",
        rows={
            @FormRowMeta(fields={
                @FormFieldMeta(field = "model.oid", type = FormFieldType.HIDDEN),
                @FormFieldMeta(title="名称",field="model.name",type=FormFieldType.TEXT,hint="请输入名称",span=12),
                @FormFieldMeta(title="单价",field="model.price",type=FormFieldType.DOUBLE,numberRange="0~",decimalCount=2,hint="请输入单价",span=12),
            }),
            @FormRowMeta(fields={
                @FormFieldMeta(title="库存",field="model.stockNum",type=FormFieldType.INT,span=12,disabled=true),
                @FormFieldMeta(title="销量",field="model.saleNum",type=FormFieldType.INT,span=12,disabled=true),
            })
        },
        buttons={
            @FormButtonMeta(title = "保存", url = "action/goodsGoodsInfo/doSave",success=FormSuccessMethod.DONE_BACK)
        },
        others= {
            @FormOtherMeta(title="商品库存",url="action/goodsGoodsStock/toList?method=goodsStockData",
                linkField=@LinkFieldMeta(field="params[goods.oid]",valueField="model.oid"))
        }
    )
    public ActionResult toEdit() throws Exception{
        if(null!=model&&!StringUtil.isSpace(model.getOid())){
            model=ModelQueryUtil.getModel(model);
        }
        return getFormResult(this,ActionFormPage.EDIT);
    }

@FormFieldMeta注解的field属性,填写action的属性.

private GoodsInfo model;
....get set ....

还有很多属性就不一一讲解了,

  • 图表功能
@ActionChartMeta(dataUrl="action/goodsGoodsOrder/goodsOrderChart",tableHeight=400,
            modelClass="goods.model.GoodsOrder",
        series = { 
            @ChartSeries(field = "saleNum", name = "数量",markPoint=true,type=ChartSeriesType.BAR),
            @ChartSeries(field = "saleAmount", name = "金额",index=1),
        },
        xAxis=@ChartXAxis(field="createDate",type=ChartAxisType.CATEGORY,dateFormat="yyyy-MM",dataZoom=true),
        querys={
            @QueryMeta(field = "goods.name", name = "名称", type = QueryType.TEXT, hint="请输入名称", likeMode=true),
            @QueryMeta(field = "createDate", name = "创建时间", type = QueryType.DATE_RANGE)
        }
    )
    public JSONMessage goodsOrderChart() throws Exception {
        return getChartDataResult(null);
    }

field和列表配置差不多
调用是在订单菜单的button上, 图表调用的是父类的toChart方法;

@ButtonMeta(title="报表",style=ButtonStyle.DEFAULT, event = ButtonEvent.MODAL,modalWidth=1000, 
    url = "action/goodsGoodsOrder/toChart?method=goodsOrderChart", 
    queryParams={
        @ParamMeta(name="params[goods.name]",field="goods.name"),
        @ParamMeta(name="params[createDatedown]",field="createDatedown"),
        @ParamMeta(name="params[createDateup]",field="createDateup"),
    }
)
  • 导出功能
    public ActionResult toExcel() throws Exception{
        ExcelObject eo=new ExcelObject("订单列表");
        ActionTableMeta meta=AnnotationUtil.getAnnotation4Method(ActionTableMeta.class, getActionClass(), "goodsOrderData");
        List<QueryCondition> list=QueryMetaUtil.convertQuery(getParams(),meta.querys());//查询条件
        eo.addSheet(super.getExcelSheet(GoodsOrderAction.class,"goodsOrderData",list.toArray(new QueryCondition[] {}),"订单列表"));
        return toExportExcel(eo);
    }

导出也是在订单的按钮上调用, 直接调用这个方法

@ButtonMeta(title="导出",style=ButtonStyle.DEFAULT, event = ButtonEvent.OPEN, 
    url = "action/goodsGoodsOrder/toExcel", 
    queryParams={
        @ParamMeta(name="params[goods.name]",field="goods.name"),
        @ParamMeta(name="params[createDatedown]",field="createDatedown"),
        @ParamMeta(name="params[createDateup]",field="createDateup"),
    }
)

返回ActionResult, 就是返回来一个jsp页面, 具体实现交给了父类.

3. Dao类

存放一些单独执行sql的方法
例如

public class GoodsInfoDao extends Dao {
    /**
     * 更新商品库存数量
     * @param goodsOid
     * @throws SQLException
     */
    public void updateStockNum(String goodsOid) throws SQLException {
        DBManager.executeUpdate("update t_goods_info set stock_num=(select sum(stock_num) from t_goods_stock where goods_oid=?) where oid=?",
            new Object[] {goodsOid,goodsOid});
    }
    /**
     * 更新商品销量
     * @param goodsOid
     * @throws SQLException
     */
    public void updateSaleNum(String goodsOid) throws SQLException {
        DBManager.executeUpdate("update t_goods_info set sale_num=(select sum(sale_num) from t_goods_order where goods_oid=?) where oid=?",
            new Object[] {goodsOid,goodsOid});
    }
}

4 .Model类

模型都放在这个包里, 需要配置config/mconfig.properties.

@TableMeta(name="t_goods_order",description="商品订单表")
public class GoodsOrder extends Model {

    @LinkTableMeta(name="goods_oid",table=GoodsInfo.class,notnull=true,description="商品")
    private GoodsInfo goods;

    @FieldMeta(name="price",type=FieldType.DOUBLE,description="销售单价")
    private Double price;
    @FieldMeta(name="sale_num",type=FieldType.INT,description="销售数量")
    private Integer saleNum;
    @FieldMeta(name="sale_amount",type=FieldType.DOUBLE,description="销售金额")
    private Double saleAmount;
    
    @FieldMeta(name="create_date",type=FieldType.DATE,description="创建时间")
    private Date createDate;
.... get set ....

需要继承Model, 继承oid主键.
可关联其他模型,数据库里对应存储该模型的oid
普通字段类型只有四种, int double date string

5. Service类

这个大家都不陌生, 业务处理类

public class GoodsOrderService extends Service {

    public String save(GoodsOrder model) throws Exception {
        model.setSaleAmount(NumberUtil.round(model.getSaleNum()*model.getPrice()));
        ModelCheckUtil.check(model);
        TransactionManager tm=new TransactionManager();
        try {
            tm.begin();
            if(StringUtil.isSpace(model.getOid())){
                model.setOid(GenerateID.generatePrimaryKey());
                ModelUpdateUtil.insertModel(model);
            }else{
                throw new MException(this.getClass(), "不允许修改");
            }
            //更新商品库存
            getDao(GoodsInfoDao.class).updateSaleNum(model.getGoods().getOid());
            tm.commit();
        }catch(Exception e) {
            tm.rollback();
            throw e;
        }
        return "保存成功";
    }
    
}

继承Service类
注: 这里使用到的ModelCheckUtil,TransactionManager,ModelUpdateUtil都是我自己写的,项目里包含源码.

6. 页面以及其他资源存放

代码中编写了一个自定义页面可供参考
调用菜单

<menu oid="B0101" sort="20101" name="首页" urlPath="page/goods/home/index.html" description="" isPublic="N"></menu>

页面基本架构

<page>
    <!-- html标签 -->
</page>
<script>
(function(){
    return { //vue对象属性
        data(){
            return {
                //key:'',
                //openKey:'',
            };
        },
        methods:{
            backHandler:function(success,msg){//打开窗体的回调
            }
        }
    };
})();
</script>
<style>
///style标签可以不写, 写的话只能是全局的
</style>

自定义页面可以参照iView https://www.iviewui.com/

基本的小例子很快就做完了, 如果熟练的话, 你们也可以很快开发后台页面.

最后放上一张效果图


测试数据可以允许/m/src_goods/goods/action/GoodsInfoAction.java的main方法.

框架是我自己一点一点搭起来的, 还有很多知识点没讲到, 但是也还有不完善的地方, 如果问题或bug, 可以给我发简信, 我会抽空完善代码, 让后台开发更便利.

相关文章

网友评论

      本文标题:03:[后台框架] 自写框架, 简单快速开发后台小示例, 已上传

      本文链接:https://www.haomeiwen.com/subject/frkcrctx.html