项目已部署好的直接更新项目就可以运行了.
没部署好的可参照序章
序:自己写的后台框架开源给大家,仅供学习,不喜勿喷.
Git地址:https://github.com/huhuanan/m
该示例已实现功能:
- 首页自定义页面;
- 三张表的定义; (启动时会自动创建)
- 三个菜单, 以及简单功能;
- 其中有个一菜单增加了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="" isPublic="N">
<menu oid="B01" sort="201" name="商品首页" icoStyle="" 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="" 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="" 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, 可以给我发简信, 我会抽空完善代码, 让后台开发更便利.
网友评论