-
一个简单的审批系统设计
2020-12-02 18:32:24一个简单的审批系统设计 1 背景 最近在做一个企业管理系统的外包,该管理系统主要分为两个端,管理端(web端)和生产端(移动端)。管理端的功能有人员管理、项目管理、工作量管理、审批流程管理等,生产端就是...一个简单的审批系统设计
1 背景
最近在做一个企业管理系统的外包,该管理系统主要分为两个端,管理端(web端)和生产端(移动端)。管理端的功能有人员管理、项目管理、工作量管理、审批流程管理等,生产端就是给员工用的,功能有上报工作量,请假,调岗,打卡等。生产端的一个特色就是有一个审批的功能,员工提交的各个模块的申请都要走审批流程,审批流程通过后,该申请才算生效。
2 审批功能设计
2.1 数据库设计
2.1.1 用例分析
一个完整的审批过程需要这几类角色:申请人、申请详情、审批流程、审批规则。
申请人点击app上面的某个申请,比如请假,然后填入必要的内容作为申请详情,比如请假原因,请假时间等(不同模块的申请,有着不同的申请详情),接着申请人指定一个审批流程后提交。审批流程中的每个审批人收到待审批的待办后依次按规则审批,通过后申请生效,驳回后申请失效。通过我的申请,已审批等页面可以查看审批详情。
2.1.2 表设计
无论是申请人,还是审批人,对应到数据库都算是一个用户,所以理所当然要有用户表。
-- users表 CREATE TABLE `users` ( `user_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '员工编码', `username` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '用户名/员工号', `password` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '密码', `phone` char(11) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '手机号', `name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '员工姓名', `dept_id` bigint(20) DEFAULT NULL COMMENT '部门编码', `dept_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '部门名称', `postion_id` bigint(20) DEFAULT NULL COMMENT '职位编码', `postion_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '职位名', `base_salary` decimal(10,2) DEFAULT NULL COMMENT '基础薪资', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `modify_time` datetime DEFAULT NULL COMMENT '修改时间', `last_login_time` datetime DEFAULT NULL COMMENT '最后登陆时间', `status` tinyint(4) DEFAULT '0' COMMENT '员工状态 0有效 1无效', PRIMARY KEY (`user_id`) USING BTREE, UNIQUE KEY `users_username` (`username`) USING BTREE, KEY `users_dept_id` (`dept_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=46 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
由于审批详情和功能模块绑定,且与审批一一对应,所以使用相同的id就可以定位到某个审批及其审批详情。而数据库就需要一张审批表(用来记录某一个审批的全部信息)和多张审批详情表(请假详情,工作量详情等)来存储数据。
审批表
-- approval表 CREATE TABLE `approval` ( `approval_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '审批编码', `module_id` tinyint(4) NOT NULL COMMENT '模块编码', `applicant_id` bigint(20) DEFAULT NULL COMMENT '申请人编码', `applicant_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '申请人名字', `approver_id` bigint(20) DEFAULT NULL COMMENT '审批人编码', `approver_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '审批人名字', `process_id` bigint(20) DEFAULT NULL COMMENT '审批流程编码', `levels` tinyint(4) DEFAULT NULL COMMENT '等级', `reject_reason` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '审批驳回原因', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `modify_time` datetime DEFAULT NULL COMMENT '修改时间', `complete_time` datetime DEFAULT NULL COMMENT '审批完成时间', `status` tinyint(4) DEFAULT '0' COMMENT '审批状态 0审批中 1审批通过 2审批驳回', PRIMARY KEY (`approval_id`) USING BTREE, KEY `index_approval_applicant` (`applicant_id`) USING BTREE, KEY `index_approval_approver` (`approver_id`) USING BTREE, KEY `index_approval_create_time` (`create_time`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=168 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
审批详情表(工作量)
在上面审批表显示的数据中其审批id为142,对应的模块id为0,也就是工作量模块(可以自定),其对应的审批详情表为work_report,而这条数据的id也是142。相应的,其他审批详情表(比如请假,调岗,离职等)也是一样。
-- work_report表 该表为工作量表, CREATE TABLE `work_report` ( `work_report_id` bigint(20) NOT NULL COMMENT '报工编码', `applicant_id` bigint(20) DEFAULT NULL COMMENT '报工申请人编码', `applicant_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '申请人名字', `sum_workload_price` decimal(10,2) DEFAULT NULL COMMENT '报工总价', `project_id` bigint(20) DEFAULT NULL COMMENT '项目编码', `project_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '项目名称', `create_time` datetime DEFAULT NULL COMMENT '创建时间', `modify_time` datetime DEFAULT NULL COMMENT '修改时间', `complete_time` datetime DEFAULT NULL COMMENT '审批完成时间', `status` tinyint(4) DEFAULT NULL COMMENT '报工状态 0审批中 1审批通过 2审批驳回', PRIMARY KEY (`work_report_id`) USING BTREE, KEY `index_work_report_user_id` (`applicant_id`) USING BTREE, KEY `index_work_report_create_time` (`create_time`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
审批流程实际上是一个个的审批人还有标志其先后顺序的审批等级。可以通过id和top_id来组织这张表。每一个process_id确定一个审批人,每一个top_id确定一个审批记录,如下图所示。
-- process表 CREATE TABLE `process` ( `process_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '流程id', `top_id` bigint(20) DEFAULT NULL COMMENT '最顶级id', `approver_id` bigint(20) DEFAULT NULL COMMENT '审核人id', `approver_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '审核人名字', `next_id` bigint(20) DEFAULT NULL COMMENT '下一流程id(null表示无后序流程)', `levels` tinyint(4) DEFAULT '0' COMMENT '流程级别(从1开始)', PRIMARY KEY (`process_id`) USING BTREE, KEY `process_top_id` (`top_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=127 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
我们看到无论是审批表还是详情表,都有一个status字段,来标志审批状态。
通过模块化的思想,可以将审批详情分为多张表。这是从审批系统的角度思考,而从各个模块的角度去想,因其都需要进行审批,所以只用一张表来存储就行,不需要为其单独的建表。
而所谓的审批规则是根据业务场景确定的,比如我这个项目,审批规则就是最简单的分级审批,每个申请只有一个审批流程,审批流程中每一级只有一个审批人,任何一级审批驳回后整个申请就宣告结束。其实只要有了基础的审批表、审批详情表、审批流程表,任何审批规则都是可以实现的,无非是复杂程度不同。
如果有查看每一级审批记录的需求,也可以再建立一张审批历史表,其中记录了每一级审批的审批人、时间等信息。
-- approval_history表 CREATE TABLE `approval_history` ( `approval_id` bigint(20) NOT NULL COMMENT '审批编码', `approver_id` bigint(20) NOT NULL COMMENT '审批人编码', `approver_name` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '审批人名字', `process_id` bigint(20) DEFAULT NULL COMMENT '审批流程编码', `levels` tinyint(4) DEFAULT NULL COMMENT '等级', `complete_time` datetime DEFAULT NULL COMMENT '审批完成时间', `status` tinyint(4) DEFAULT '0' COMMENT '审批状态 0审批通过 1审批驳回', PRIMARY KEY (`approval_id`,`approver_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
2.2 功能拆分
通过对用例的分析,设计出了五张表。分别是用户表、审批表、审批详情表、审批流程表和审批历史表。
在审批表和审批详情表之间通过相同的id进行数据绑定,并且根据模块id来确定不同的审批详情。接下来就是设计功能,来支撑起整个审批系统了。
2.2.1 对于审批流程的思考
对于整个审批的操作大致可以分为四块,即:1 上报申请,2 通过申请,3 驳回申请,4 查看申请详情。
对应到数据库层面的操作就是:1 开启一级审批流程;生成审批表记录;审批详情表记录,2 修改审批状态为通过,3 修改审批状态为驳回,4 查询审批表及其详情。
最难的是上报,其次是查询,最后是通过/审批,体现在代码层面就是其代码行数的减少。而整个线性的审批流程,也正对应着其开发流程。
抽象出来的四个操作,完全适用于每个功能模块,对应到代码层面就是四个接口。前端完全可以通过这四个接口来完成不同功能模块审批操作,只需要向后端传输相应的模块id即可。该抽象思想,也可以用在数据校验上,后面做数据校验时也会用到类似抽象的思想。
2.2.2 四大接口
话不多说上代码
2.2.2.1 举一反三设计上报接口
上报的流程大致分为三个:1 生成审批,2 生成审批详情,3 通知第一审批人审批
/** * 审批上报 * * @param input * @return */ @RequestMapping(value = "/reporting", method = RequestMethod.POST) @Approval(opType = Approval.REPORTING) @Transactional public RespBean reporting(@RequestBody Input input) { // 开启审批流程 approvalService.addApproval(input); // 上报 input.getService().reporting(input); // 生成待办 todoService.generateTodo(input); return RespBean.ok("上报成功"); }
approvalService:用来操作审批,主要有以下四个操作
public interface IApprovalService { // 生成审批 void addApproval(Input input); // 查询审批详情 JSONObject getApprovalDetail(Input input); // 审批通过 void passApproval(Input input); // 审批驳回 void rejectApproval(Input input); }
在上报接口中,调用addApproval方法使用其来生成审批,并返回其id,来供下游生成同id的审批详情。
接着就是模块的上报流程,其实就是从入参中获取对用service层的类,调用reporting方法。而不同的service都会实现同一个接口:IApprovalDetailService,实现该接口的业务类,执行不同的业务操作。
public interface IApprovalDetailService { // 执行上报 void reporting(Input input); // 查询审批详情 JSONObject todoDetail(JSONObject res); // 完成整个审批 void pass(Input input); // 审批驳回 void reject(Input input); }
上报完成后,就可以调用todoService生成待办给审批人看了
public interface ITodoService { // 生成待办 void generateTodo(Input input); // 审批通过 完成代办 void pass(Input input); // 审批驳回 完成待办 void reject(Input input); // 查询待办 Todo getTodo(Long todoId, Long userId); }
其余三个操作的流程附上
/** * 查看审批详情 * * @param input * @return */ @RequestMapping(value = "/todoDetail", method = RequestMethod.POST) @Approval(opType = Approval.TODO_DETAIL) public RespBean todoDetail(@RequestBody Input input) { // 查询审批详情 JSONObject approvalRes = approvalService.getApprovalDetail(input); // 查询业务详情 JSONObject res = input.getService().todoDetail(approvalRes); return RespBean.ok("查询成功", res); } /** * 审批通过 * * @param input * @return */ @RequestMapping(value = "/pass", method = RequestMethod.POST) @Approval(opType = Approval.PASS) @Transactional public RespBean pass(@RequestBody Input input) { // 完成待办 todoService.pass(input); // 通过审批 并 尝试推进下一审批 approvalService.passApproval(input); if (null == input.getApproval()) { // 完成整个审批流程 input.getService().pass(input); } else { // 如果审批未完成 就生成待办(新审批) todoService.generateTodo(input); } return RespBean.ok("审批通过成功"); } /** * 审批驳回 * * @param input * @return */ @RequestMapping(value = "/reject", method = RequestMethod.POST) @Approval(opType = Approval.REJECT) public RespBean reject(@RequestBody Input input) { // 完成代办 todoService.reject(input); // 结束审批流程 approvalService.rejectApproval(input); // 结束业务流程 input.getService().reject(input); return RespBean.ok("审批驳回成功"); }
2.3 AOP根据自定义注解确定运行时接口
在四大接口执行之前,需要做的事也有很多,如参数校验,参数注入。而这些操作通过AOP可以统一去做。
只需要根据前端传入的模块id,就能够确定相应的校验器和业务类。
AOP中的代码复用,使用到了java反射,通过获取到运行时触发方法上的注解,来判断调用了哪个接口,从而注入不同的参数,供下游使用。
比如在校验时,通过实现定义好的枚举类,使用前端传入的模块id找到相应的beanName,然后通过ioc容器获取对应的校验器bean,执行相应的校验方法。而不同模块的校验器实现已经做好了参数校验,下游直接执行业务代码即可。
Valid接口
/** * @author: theTian * @date: 2020/11/12 15:02 */ public interface Valid { /** * 上报验证 * @param input */ void validReporting(Input input); /** * 查询审批验证 * @param input */ default void validTodoDetail(Input input){}; /** * 审批通过验证 * @param input */ default void validPass(Input input){}; /** * 审批驳回验证 * @param input */ default void validReject(Input input){}; }
在获取相应的业务bean时,也用到了相同的想法,即通过模块id找到对应的业务bean。其中获取bean借助到了ioc容器,所以枚举类中的beanName要和ioc中的beanName一致。
/** * 审批四个接口的参数校验及参数注入 * * @param point * @throws Throwable */ @Around("execution(* x.x.controller.ApprovalController.*(x.x.x.Input))") public Object approvalValid(ProceedingJoinPoint point) throws Throwable { Input input = (Input) point.getArgs()[0]; logger.info(point.getSignature().getName() + "入参:" + input); // 根据注解注入参数 Signature signature = point.getSignature(); MethodSignature msg = (MethodSignature) signature; Method method = point.getTarget().getClass().getMethod(msg.getName(), msg.getParameterTypes()); Approval annotation = method.getAnnotation(Approval.class); String opType = annotation.opType(); if (StringUtils.isNotEmpty(opType)) { input.setUser(UserUtils.getUser()); input.setValidMethod(opType); } // 校验 ValidUtils.approvalValid(input); // 获取service ApprovalService service = ServiceFactory.getService(input.getModule().getModuleId()); JgerpAssert.notNull(service, "不存在该服务"); // 装填service input.setService(service); // 执行后序方法 RespBean res = (RespBean) point.proceed(); logger.info(point.getSignature().getName() + "出参:" + JSONObject.toJSONString(res)); return res; }
核心代码:
// 校验 ValidUtils.approvalValid(input); // 获取service ApprovalService service = ServiceFactory.getService(input.getModule().getModuleId());
3 总结
在参考网上的博客,结合项目实际情况后逐渐找到了思路。其实就是在设计各种功能的时候考虑到要做模块化,把审批系统,各个功能模块独立出来,一定要降低模块之间的耦合度,并提升自身模块的复用性,这样的好处就是在开发了审批系统之后开发新的功能模块时,就可以直接接入已经做好的审批系统,从而达到代码复用。
可是知易行难,真正落实到代码层面,需要注意很多的细节。
比如,由于是前后端分离开发,要考虑到各个功能模块的数据校验。起码不能因为字段过长而导致插入数据库失败,与此同时也要考虑特殊字符处理,业务规则校验等。
再比如审批系统设计的要足够独立,对于新模块的开发,要做到一次开发,处处使用。这就需要运用到OOP以及AOP的思想。
随着项目的推进,如今一期的基本功能都已经实现了,但仅仅只做到了够用,自己的设计肯定不是业界最佳方案,也可能隐藏着诸多的漏洞,但是从需求分析,功能设计,数据库设计,功能开发和测试,在这个过程中通过思考问题并实践验证,确实收获很多。
-
一个简单嵌入式WEB业务应用设计
2016-05-19 15:17:45一个简单嵌入式WEB业务应用设计 主要是针对之前产品中WEB应用的设计的重构,把业务与一些东西分离出来,方便维护,本身比较简单, 注意这个不是说写WEB服务程序的。 工具 goahead json-c jquery 数据交互 ...一个简单嵌入式WEB业务应用设计
主要是针对之前产品中WEB应用的设计的重构,把业务与一些东西分离出来,方便维护,本身比较简单, 注意这个不是说写WEB服务程序的。
工具
goahead
json-c
jquery
数据交互
WEB服务与主应用交互
WEB服务进程同应用进程在同一个嵌入式系统中,两个进程的交互使用UNIX域UDP方试通讯,主要的是数据是,WEB前端的数据请求,数据的提交或控制命令,数据都用json的格式传输。
WEB服务与WEB前端交互
WEB前端的HTML请求都通过goahead处理了,在数据上面,我们用AJAX传输JSON的方式,goahead通过UDP服务转给主应用,主应用处理后返回进goahead,再回应给WEB前端。
之所以用UNIX域UDP通信,一个是速度,也可靠,JSON交换的数据也不是太大,双向通信,简单,包与包之前不用再去分隔了。
WEB服务端
Web服务使用开源的goahead这个工具,它相对于WEB前端来说是一个服务端,在与我们的主应用来说又是一个UNIX域UDP客户端。
WEB服务端的初始化
Goahead的初始化可以参见它的例子中,其实我对这个工具也不太熟悉,在它提供的例子里来改一下,它的初始化操作中有一个initWebs 的过程,这里面设置了一些必要的参数,如默认的网页,比如我的设置的是 index.html 是一个宏定义的:
#define WEBS_DEFAULT_HOME T("index.html") /* Default home page */
#define WEBS_DEFAULT_PORT 80 /* Default HTTPport */
#defineWEBS_DEFAULT_SSL_PORT 433 /* Default HTTPSport */
分别定义了默认的主页,端口。
因为要与主应用中通讯,使用的是UNIX的域UDP方式,所以在goahead里我们要初始创建一个socket的来与主应用交互。
在一个合适的地方,定义一个Web_Client_init,它的作用就是初始化创建一个UNIX的域UDP socket而已,所以在initWebs中调用过程: Web_Client_init()。
在一个合适的地方,定义一个 int Web_Client_Send(char* buf, int len, char* recvbuf, int* maxlen), 用它来把WEB前端的数据转发给主应用,同时接收主应用的回应。
在goahead里接收WEB前端过来的AJAX 请求json数据,做如下的动作:
设置一个URL请求的处理过程:
websUrlHandlerDefine(T("/ajax/json_data"),NULL, 0, ajax_json_data, 0);
这果 URL 为 http://xxxx/ajax/json_data 这样的URL过来的数据,都传给ajax_json_data处理了。如我的如下的处理,
#define RECV_BUF_LEN 2048
static charRECV_BUF[RECV_BUF_LEN];
int ajax_json_data(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg,
char_t *url, char_t *path, char_t *query)
{
int ret;
char* data = websGetVar(wp,T("data"),"");
int len = strlen(data);
//ret = WebMsg_Send(data, len);
//char recvbuf[1024] = {0};
int recvlen = RECV_BUF_LEN;
RECV_BUF[0]= 0;
ret= Web_Client_Send(data, len, RECV_BUF, &recvlen);
if(ret == 0)
{
if(recvlen == 0)
{
websWrite(wp,T("{status:'failed', data:'Server nodata!'}"));
}else{
websWrite(wp,RECV_BUF);
}
}else{
websWrite(wp,T("{status:'failed'}"));
}
websDone(wp,200);
return 1;
}
一般JSON的请求数据都不大太,注意空间的分配,上面的过程就是调用 Web_Client_Send 把数据发给主应用,主应用处理完后,同样返回的是JSON格式的应答,获取主应用的应答后通过websWrite写回给WEB前端,注意 websGetVar 获取数据的方式,找的是名为”data”的,这个是在WEB网页中JS里定义的,原因是我们的JS代码是这样写的:
functionajaxActionWrap(actionData, callback)
{
$.post(URL_AJAX_ACTION,
{
data: actionData,
},
function(data, status){
if(callback)
callback(data, status)
}
);
}
这样完成后,我们的WEB服务端的事就完成了,它的作用就是负责传输数据,把它同业务分它了。
主应用
主应用的一个任务是要接收WEB服务传过来的WEB前端请求。
创建一个UNIX域UDP服务。比如我们在一个合适的地方创建一个初始化启动服务的方法: Web_Server_Init(),这样就能接收到WEB的请求了。
另一个任务就是对WEB的AJAX JSON请求的处理回应了。
不同的JSON调用,针对不同的业务,所以我们定义一个记录不同业务处理过程的结构:
比如:
typedef int (*JsonActionProc)(char* data, void* jsonobj,AjaxActionProcCallBack cb);
typedef struct _WebAjaxAction{
char* actionName;
JsonActionProc actionProc;
}WebAjaxAction;
actionName是对应处理方法的标识,如WEB前端传一个这样的JSON数据过来:
{"action":"wifi_status","data":{"p1":1,"p2":2}}
那么 wifi_status 就是对应actionName.
记录注册每一个json里的action调用过程,如:
static WebAjaxActionwebAjaxActionList[] = {
{"wifi_status",wifi_status},
{"wifi_scan",wifi_scan},
{"wifi_get_aplist",wif_get_aplist},
{"wifi_conn",wifi_conn},
{"wifi_getAplist",wifi_getAplist},
};
像wifi_status,wifi_scan… 这些都是调用方法的标识,这个要与WEB前端协商好,保持一致。
actionProc 参数就是对应的调用方法了。
上面的过程,也就是如 WEB 传一个JSON数据过来,它里面有对应的actionName,通过actionName找到对应的业务方法,JSON里也会有一些参数,把JSON里的数据解析出来,调用对应的业务方法就行了,同时把处理的过后的数据通过WEB服务端返回的WEB前端。
从上面的过程,来说,调用recvfrom接收到数据报后,调用一个过程,从webAjaxActionList 里找到对应的处理方法,调用处理方法,处理方法完成后,把要返回的数据通过sendto 再回到WEB服务端,再返回的WEB前端。整个过程就完事了。
WEB前端
完成上面的东西,WEB前端就可认方便的调用了,当HTML显示加载完成后,再通过AJAX的方式,用JSON的格式来调用数据。
如我的获取一个WIFI的连接状态,当然,交互的JSON数据需要WEB前端与主应用后端要协商好,用什么样的格式,比如我的是:
{"action":"wifi_status"}
表示调用的方法是 wifi_status
如下面的几个相关的方法:
/*获取WIFI连接状态*/
functiongetWifiStatus()
{
var data ='{"action":"wifi_status"}';
ajaxActionWrap(data,getWifiStatusCallBack);
}
functionajaxActionWrap(actionData, callback)
{
$.post(URL_AJAX_ACTION,
{
data: actionData,
},
function(data, status){
if(callback)
callback(data,status)
}
);
}
functiongetWifiStatusCallBack(data, status)
{
if(status != "success")
{
alert("get wifi statusfailed!\n");
return;
}else{
var jobj = eval(data)
if(jobj)
{
$("#wifiCurAp").html(jobj[0].wifi_status.ssid);
if(jobj[0].wifi_status.status== 1)
$("#wifiCurStatus").html("已连接");
else
$("#wifiCurStatus").html("未连接");
}else{
$("#wifiCurStatus").html("未连接");
}
}
}
在后端,它会找到wifi_status的对应处理方法,处理后返回定义好的JSON数据格式,WEB前端再显示出来。
最后
通过上面的处理方式,对于主应用来说,把业务相关的都隔离开了,在对应的处理方法中,WEB服务端只负责传输数据,WEB前端通过AJAX的方式传输JSON数据和接收,通过JS脚本控制。
在添加新的业务时,也只要修改WEB前端的JS脚本,主后端注册一下处理的方法就行。
注:对WEB应用只懂一点点,对上面的实现提一点注意的地方:
1:JS脚本里最好不要用eval转换数据生成对像,不安全,可以用jQuery里的对应工具。
2:AJAX的请求认证,一定要记得添加,像上面的应用的话,比较好的方式可以加在WEB服务端的ajax_json_data 里,在请求后端应用时,验证一下,见很多产品,AJAX请求尽然没有验证权限。
-
设计一个简单的JAVA_Web项目
2020-12-10 18:41:26一、设计一个Java web信息系统,可以选择如下题目,也可以自拟其它题目: 1.大学生体测信息管理系统 2.实验室科研信息管理系统 3.小区物业管理信息系统 4.健身俱乐部会员... -
一种简单的web应用系统界面设计
2012-01-04 23:26:10[size=x-small]本人初学java,最近做一个管理系统,界面按照以下...具体在系统中的应用是:系统主界面留有足够空白(位于浏览器的中间右边矩形区域,就是一个div)给各个菜单项展示界面,点击菜单项之后通过获取js...[size=x-small]本人初学java,最近做一个管理系统,界面按照以下方法实现:
将html文件直接打印到response输出流中,界面效果采用js或者css方式实现。
可以在xml中配置针对各个不同的风格、浏览器的界面效果的js和css代码。
具体在系统中的应用是:系统主界面留有足够空白(位于浏览器的中间右边矩形区域,就是一个div)给各个菜单项展示界面,点击菜单项之后通过获取json对象来对界面空白div进行html赋值,然后更新css或者执行js代码完成界面绘制。json对象由后台给出,根据用户信息将html文件中的字符串和js的function组成json对象打印到response中,完成界面之后更新css文件的url。
这种实现方式采用的都是最基础的方式,我觉得非常灵活,由于我没有学习过界面框架,恳请大家提出建议和想法。[/size] -
简单系统的web层的前端设计
2020-05-16 14:53:524】Bootstrap+jQuery(Boostrap做页面的布局、样式的控制,jQuery做交互的一个实现) 一:前端用户设计,根据需求设计,涉及三个职位: 产品(解决用户需求,设计满足用户需求的文档)+前端(负责满足不同平台的...个人秒杀系统小项目前端+后端的流程设计思路
1】前端交互设计
2】Restful接口(设计URL的设计规范,互联网公司常用的规范)
3】Spring Mvc
4】Bootstrap+jQuery(Boostrap做页面的布局、样式的控制,jQuery做交互的一个实现)
一:前端用户设计,根据需求设计,涉及三个职位:
产品(解决用户需求,设计满足用户需求的文档)+前端(负责满足不同平台的页面展示,比如PC端,移动端)+后端(存储、展示)
二:前端页面的流程
详情页:
用户处于不同的时区,用户的时间都不一致,所以就有必要统一标准时间(服务器的时间)
-
ASPNET学习单元1 认识ASPNET并设计一个简单的ASP.NET Web应用程序.ppt
2020-02-04 13:12:56应用程序开发技术 学习单元1 认识并设计一个简单的 Web应用程序 1.1 认识.NET Framework 图1-1所示 Web应用程序是运行在.NET Framework基础上B/S架构的Web应用程序 1.1 认识.NET Framework .NET Framework组成 提供... -
web-app-challenge:一个简单的Web应用程序-源码
2021-02-21 07:18:40为了完成这一挑战,您将需要编写一个简单的餐厅订购Web应用程序,并在完成项目后通过发送github存储库的链接来提供源文件。 系统将要求您在或 javascript框架中构建项目。 如果没有使用任何一种框架的经验,则可以... -
一个简单系统的设计之争
2010-09-20 17:00:00一个简单系统的设计之争 蒋彪@南京 2010-9-20 1. 前言 一个朋友最近在做一个小项目,想让我去评审评审设计,于是我就去听了听他们的设计,同时提出了自己的一点思路,发现了一点有趣的事情。 抛开业务,这个... -
一个简单的入门Java web项目
2019-07-09 11:21:16引言:商城订单管理系统属于小型的Java web系统,由java web+mysql+servlet实现,采用mvc的设计模式,jdbc编程,具备增删改查以及模糊查询,用户登陆注册的功能,版本为eclipse版,如果需要别的版本如idea版,系统... -
中小企业设计一个基于WEB的项目管理系统需要什么开发工具呢
2020-11-07 18:17:52一家文化公司项目较多历史跨度也比较大,执行环节也不少,以前的项目管理都是简单的人工统计外加Excel数据处理。 现在项目扩充到数百个,原来的统计和管理方法渐渐的跟不上了。想设计一套基于web的PM。因为是程序... -
Jsp+JavaBean+Servlet的简单大学的web课程设计(二手房屋交易系统)
2011-01-19 15:22:43所以这个修改一下交一般的Web jsp的设计没问题的,里面唯一不足的就是显示分页那一板块,有一个DAO文件,里面弄得差不多了,差一个Servlet调用就行了,其他的都很简单,但是MVC弄得很好的。 因为是便于交作业的参考... -
基于java web的简单bbs论坛系统
2013-06-19 10:38:06一个简单的java web数据库程序设计,关于简单的bbs的论坛系统 -
[web应用] “简单的健康信息记录系统”的设计文档
2020-06-30 13:54:18本文描述笔者做的一个基于lamp(Linux+Apache+MySQL+PHP)开发的简单的web应用,该应用采取的架构风格为以数据为中心的“仓库”风格,主要模块是php与mysql交互的部分。本文是从初学者角度尝试着写的,用于学习交流... -
简单的嵌入式web服务器设计
2019-06-01 17:54:18浏览器是个显示网页伺服器或档案系统内的HTML文件,并让用户与此些文件互动的一种软件。个人电脑上常见的网页浏览器包括Internet Explorer、Firefox、Safari。浏览器是最经常使用到的客户端程序。 WEB服务器 Web... -
Fizzygum:一个全新的Web框架,实际上是一个完整的平台,从头开始设计,可轻松处理复杂的事情。 轻松掌握...
2021-02-04 10:15:17尝试一个可以轻松处理复杂事物的新Web框架。 Fizzygum从头设计到: 制作仪表板并可视化数据(图表,地图等) 创作,组织和浏览文档 通过简单的拖放操作,可在任何地方插入动态计算 直观地制作自定义实用程序... -
模式系统与最简单的Node.js MVC Web Server设计
2018-01-12 22:53:55学了这么久的设计模式,最近一直在看Node.js的设计模式,一直纳闷...面对特定问题时,专家很少去寻找与既有解决方案截然不同的新方案,而通常会想起一个以前解决过的类似问题,并将其解决方案的精髓用于解决这个新问... -
eth-ipfs:一个简单的Web应用程序,用于使用以太坊和IPFS上载和存储文件-源码
2021-02-04 14:48:24一个简单的Web应用程序,用于使用以太坊区块链和行星际文件系统(IPFS)上传和存储文件。 使用Mocha和React设计和测试,以供浏览器与Metamask一起使用。 Dapp前端部署在Rinkeby测试网络上的上。 在注册并验证的... -
python账号管理web系统_我的第一个python web开发框架(34)——后台管理系统权限设计...
2020-12-08 23:43:11小白:老大,上次你对后台权限系统简单的讲了一下,我一点头绪都没有,现在有空完整的说一说吗?老菜:说到权限系统,要讲明白真不容易,权限系统并不是越复杂越好,要根据项目的需要而定,有的系统只有几个人操作,... -
20145303 20145339 《信息安全系统设计基础》 实验五 简单嵌入式WEB服务器实验
2016-12-25 16:18:001、掌握在ARM开发板实现一个简单WEB服务器的过程 2、学习在ARM开发板上的SOCKET网络编程 3、学习在Linux下的signal()函数的使用 实验内容 学习使用socket进行通讯编程的过程,了解一个实际的网络通讯应用程序整体... -
java web课程设计(简单商城的前后端双系统,基于maven三模块开发)
2018-12-28 21:44:13实现一个简单但功能完整的商城项目,从设计到实现,规范化完成该项目,锻炼javaweb项目的编写能力,理解软件工程的软件设计思想 1.2编程技术简介 本次课程主要使用的软件有Intellij IDEA、Navicate for MySql、... -
SNMP代理和Web网管系统的设计与实现
2021-01-31 11:15:17随着网络规模不断扩大,网络结构日益...设计实现了一个基于Web技术且支持SNMP协议的网络管理系统。该系统汲取了SNMP的简单、易用、应用广泛的优点,同时又融入了Web技术,使该系统具有了可移动性和平台独立性等特点。 -
我的第一个python web开发框架(34)——后台管理系统权限设计
2018-08-22 19:36:00小白:老大,上次你对后台权限系统简单的讲了一下,我一点头绪都没有,现在有空完整的说一说吗? 老菜:说到权限系统,要讲明白真不容易,权限系统并不是越复杂越好,要根据项目的需要而定,有的系统只有几个人... -
简单的Java web项目源码(10个)
2019-09-04 14:25:19引言:Java web项目主要采用mvc的的设计思想,系统主要采用java+jsp+servlet+mysql+eclipse实现,具有登陆、分页、导出excel,增删改查等功能,适合初学者,满足基本的实训需求,以下是推荐的几款,总有你喜欢的一个 ... -
我的AI之路(26)--使用ROSBridge WebSocket和roslibjs构建一个简单的控制机器人的web demo
2019-02-09 16:07:02在一个复杂的机器人后端控制平台系统开发完成以前,往往需要对你的机器人产品进行简单的软件架构设计验证或进行控制测试,这时,如果能花比较少的时间快速做一个web页面或者一个Android app来作此用途的话能节省不少... -
cloudopt-next:一个简单而现代的Java和Kotlin vert.x Web框架-源码
2021-02-03 23:10:32简单的极简主义设计,几乎没有配置,不依赖于tomcat,码头和其他Web容器。 Asyn基于vertx,很容易实现高性能的异步服务。 插件支持vertx系统的各种组件,还支持通过插件扩展功能。 官方还提供了大量有用的插件。 ... -
学号20145332 《信息安全系统设计基础》实验五 简单嵌入式WEB服务器实验
2016-11-13 15:36:00掌握在 ARM 开发板实现一个简单 WEB 服务器的过程。 学习在 ARM 开发板上的 SOCKET 网络编程。 学习 Linux 下的 signal()函数的使用。 实验内容 学习使用 socket 进行通讯编程的过程,了解一个实际的网络通讯应用... -
简单web系统理解JavaBean、DAO、VO和servlet(一)
2020-09-16 13:22:19此处用的是一个java web系统的一个staff表操作的模块,核心部分包括表的设计、数据库连接、数据封装类(VO)的创建、封装业务的JavaBean(DAO)、servlet和jsp结合对数据库进行操作和显示。其他业务的操作大同小异。 ...
-
C++MFC开发远程控制软件教程(VS2013)
-
Docker从入门到精通
-
MySQL 多实例安装 及配置主从复制实验环境
-
Monkey_test.zip
-
项目经理成长之路
-
用微服务spring cloud架构打造物联网云平台
-
iptables 企业级防火墙配置(四表五链)
-
华工信号与系统真题与详解.zip
-
MySQL 高可用(DRBD + heartbeat)
-
HTML5动态效果制作方法整理
-
面试简历制作简历篇.ppt
-
二极管抽运全固态1.319 μm连续锁模激光器
-
clickhouse20.9.2.20-2..zip
-
工程制图 AutoCAD 2012 从二维到三维
-
02. Ubuntu终端操作与Shell命令
-
基于信息分离和邻居惩罚选择的多目标优化
-
健康生活起居
-
04. ubuntu磁盘管理
-
FastDFS 分布式文件系统部署
-
Unity ILRuntime框架设计