xiaoya
本系统的最终用户为系统管理员和小区住户。该系统的成功开发,将可以巨大便利系统管理员对住户信息的统计与管理。根据查询资料及对相关人员的咨询,我们讨论分析,得出小区管理员和小区住户对本系统的实际要求:
小区管理员应对小区可用资源得信息进行及时地完善和更新,对小区内所有住房的居住情况和车位的租借情况统计整理,并向有需求的住户提供有效信息和便利服务。
住房居住的基本信息
小区管理员应对小区内所有住房被使用情况进行实时地完善与更新,以方便有需求的住户使用。这些住房信息应该包括住房号码,住房状态(使用状态和空闲状态),住房地址,住房所属区域。
车位租借的基本信息
小区管理员应对小区内的所有车位租借情况进行实时地完善与更新,以方便有需求的住户租借。车位租借的情况应包括车位号码,车位地址,租借状态(使用状态和空闲状态)
当住户入住该小区后,通过手机端APP,登记住户个人信息,以方便小区管理员对住户进行管理,与住户进行必要的业务交流。住户需要登记以下信息。
住户登录的基本信息
登录手机APP时,每位住户通过注册自己的手机号码和登录密码来获得小区 服务的权限,而系统会为每位住户指定一个唯一的用户ID,用于后台信息的 统计和管理。
小区住户的基本信息
每位小区住户都具有必要注册的个人信息,以保证小区内住户个人信息的完 整性,确保小区住户们的安全,其中包括系统为每位住户指定的唯一ID,身 份证号码,姓名,性别,手机号码,年龄,民族,职业,住房号码,登录APP 密码。
信息要求
处理要求
安全性与完整性要求
信息要求
处理要求
安全性要求
根据如上得到的用户需求,我们将本系统按照所完成的功能分成以下两部分:
注册个人信息
根据手机号与登录密码登录
发起投诉或报修
查看发起的投诉或报修
查看剩余车位的数量
租用车位
结束租用车位
获得最新的一条公告
注册新的管理员
根据账号密码登录管理平台,登记查看修改删除小区人员信息
登记查看修改删除小区租房信息
登记查看修改删除车位信息
解决报修或投诉
查看租借信息
发布查看修改删除通知信息
查看统计信息
总数据流图如图所示:
房间信息分数据流图如图所示:
用户信息分数据流图如图所示:
通知信息分数据流图如图所示:
车位信息分数据流图如图所示:
租借信息分数据流图如图所示:
报修投诉信息分数据流图如图所示:
管理员信息分数据流图如图所示:
本系统基于guns开源框架。框架基于SpringBoot 2,整合springmvc + mybatis-plus + echarts。Spring Boot是一种JAVA框架,旨在尽可能快地启动和运行,只需最少的Spring前端配置。Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。MyBatis是一个支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及对结果集的检索封装。MyBatis可以使用简单的XML或注解用于配置和原始映射,将接口和Java的POJO(Plain Old Java Objects,普通的Java对象)映射成数据库中的记录。Echarts缩写来自Enterprise Charts,商业级数据图表,它最初是为了满足公司商业体系里各种业务系统的报表需求。
关于系统架构采用的是MVC架构 ,它全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。其逻辑图如下图所示:
视图:将视图层存放在PeopleManage\src\main\webapp中,其子文件夹static\modular存放各个业务功能的JavaScript代码,另一个子文件夹WEB-INF\view 存放各个业务功能的HTML代码
控制器:将控制器存放在PeopleManage\src\main\java\cn\stylefeng\guns\modular的各个业务功能的controler文件夹中
模型:将模型存放在PeopleManage\src\main\java\cn\stylefeng\guns\modular\system\model中,各个模型通过其对应的Mapper.xml进行需要的sql查询,通过Mapper接口类来调取Mapper.xml,sql查询的结果。若模型的业务逻辑复杂,将多增加对应的Service类来组合形成更复杂的业务逻辑,使业务逻辑更清晰有条理
本系统的增删查改模式基本都类似,只是有些具体的业务有不同的需求,系统会有相应的处理,总体框架是没有变的。现在以住房管理为例,详细说明本系统增删查改的逻辑。
首先用户看到的应该是住房管理的主页面,如图所示:
本界面存储在 PeopleManage\src\main\webapp\WEBINF\view\room_info\info\info.html
其HTML代码如下:
<div class="ibox float-e-margins">
<div class="ibox-title">
<h5>住房管理</h5>
</div>
<div class="ibox-content">
<div class="row row-lg">
<div class="col-sm-12">
<div class="row">
<div class="col-sm-3">
<#NameCon id="condition" name="名称" />
</div>
<div class="col-sm-3">
<#button name="搜索" icon="fa-search" clickFun="Info.search()"/>
</div>
</div>
<div class="hidden-xs" id="InfoTableToolbar" role="group">
@if(shiro.hasPermission("/info/add")){
<#button name="添加" icon="fa-plus" clickFun="Info.openAddInfo()"/>
@}
@if(shiro.hasPermission("/info/update")){
<#button name="修改" icon="fa-edit" clickFun="Info.openInfoDetail()" space="true"/>
@}
@if(shiro.hasPermission("/info/delete")){
<#button name="删除" icon="fa-remove" clickFun="Info.delete()" space="true"/>
@}
</div>
<#table id="InfoTable"/>
</div>
</div>
</div>
表格显示的位置在<#tableid=”InfoTable”/>,表格由其对应的JavaScript向Controller发出请求获得数据。控制住房管理的JavaScript存放在 PeopleManage\src\main\webapp\static\modular\room_info\info\info.js 中。
其代码如下:
/**
* 住房管理初始化
*/
var Info = {
id: "InfoTable", //表格id
seItem: null, //选中的条目
table: null,
layerIndex: -1
};
/**
* 初始化表格的列
*/
Info.initColumn = function () {
return [
{field: 'selectItem', radio: true},
{title: '区域标识号', field: 'room_id', visible: true, align: 'center', valign: 'middle',width:"100px"},
{title: '名称', field: 'name', visible: true, align: 'center', valign: 'middle'},
{title: '地址', field: 'address', visible: true, align: 'center', valign: 'middle'},
{title: '类型', field: 'type', visible: true, align: 'center', valign: 'middle',
formatter: function(value,row,index){
if(row.type==true)
{
value='<div style="text-align: center;" ><i class="fa fa-bed"></i> 房间</div>';
}
else value='<div style="text-align: center;" >区域</div>';
return value ;
}},
{title: '父节点', field: 'parent_id', visible: false, align: 'center', valign: 'middle'}
];
};
$(function () {
var defaultColunms = Info.initColumn();
var table = new BSTreeTable(Info.id, "/info/list", defaultColunms);
table.setExpandColumn(2);
table.setIdField("room_id");
table.setCodeField("room_id");
table.setParentCodeField("parent_id");
table.setExpandAll(true);
table.init();
Info.table = table;
});
JavaScript页面中的表格控制工具BSTreeTable向Controler发出请求,请求地址为info/list,Controler接收到请求后返回所需的信息,BSTreeTable根据后端返回的信息对后端返回的信息进行处理,table.init初始化函数对返回的数据进行处理,formatter函数对房间类型进行处理,当房间类型为1时显示为房间,当房间类型为0时显示为区域。
房间管理的控制器位置在 PeopleManage\src\main\java\cn\stylefeng\guns\modular\room_info\controller\InfoController.java,控制器收到/info/list请求地址后执行list函数,list函数调用infoService.list方法后返回房间管理的列表,再使用RoomWarpper处理数据,最后返回给BSTreeTable显示到前端页面中。控制器代码如下:
/**
* 住房管理控制器
*/
@Controller
@RequestMapping("/info")
public class InfoController extends BaseController {
private String PREFIX = "/room_info/info/";
/**
* 获取住房管理列表
*/
@RequestMapping(value = "/list")
@ResponseBody
public Object list(String condition) {
List<Map<String, Object>> list = this.infoService.list(condition);
return super.warpObject(new RoomWarpper(list));
}
}
infoService中的list方法,在InfoMapper.xml中实现,其代码如下所示:
<select id="list" resultType="map">
select * from info_room
<if test="condition != null and condition != ''">
where address like CONCAT('%',#{condition},'%')
</if>
</select>
经过上述各个步骤,数据才能从数据库中取出来,放到前端界面进行展示。
在info.html页面点击添加按钮,info.javascrpit会向控制器发送一个添加请求,请求地址为/info/info_add,其代码如下所示:
Info.openAddInfo = function () {
var index = layer.open({
type: 2,
title: '添加住房',
area: ['800px', '420px'], //宽高
fix: false, //不固定
maxmin: true,
content: Feng.ctxPath + '/info/info_add'
});
this.layerIndex = index;
};
当InfoController接收到/info/info_add请求后会返会info_add.html页面,其代码如下所示:
@RequestMapping("/info_add")
public String infoAdd() {
return PREFIX + "info_add.html";
}
info_add.html页面如图所示:
控制此页面的JavaScript是info_info.javascript,其主要代码如下所示:
/**
* 初始化住房管理详情对话框
*/
var InfoInfoDlg = {
infoInfoData : {}
};
/**
* 收集数据
*/
InfoInfoDlg.collectData = function() {
this
.set('roomId')
.set('type')
.set('name')
.set('parentId')
.set('address')
}
/**
* 提交添加
*/
InfoInfoDlg.addSubmit = function() {
this.clearData();
this.collectData();
//提交信息
var ajax = new $ax(Feng.ctxPath + "/info/add", function(data){
Feng.success("添加成功!");
window.parent.Info.table.refresh();
InfoInfoDlg.close();
},function(data){
Feng.error("添加失败!" + data.responseJSON.message + "!");
});
ajax.set(this.infoInfoData);
ajax.start();
}
当用户填完所有信息,点击提交按钮时,会向后端送请求,请求地址为info/add,参数为填写的信息。
当InfoControler接收到此信息时会调用add函数,add函数会判断其是不是顶层区域,如果是顶层区域,此房间的地址就是房间名,如果不是顶层区域,此房间的地址就是上一层房间的地址再加上此房间名。然后使用mybatis简化的插入方法,infoService.insert(info)函数将信息插入到数据库中。其实现代码如下所示:
@RequestMapping(value = "/add")
@ResponseBody
public Object add(Info info) {
if(info.getParentId()!=0)
info.setAddress(infoService.selectById(info.getParentId()).getAddress()+info.getName());
else info.setAddress(info.getName());
infoService.insert(info);
return SUCCESS_TIP;
}
在info.html选中一条记录,再在页面点击修改按钮,info.javascrpit会找到选择记录的id,然后向Controller发送修改请求,请求地址info/info_update,当请求完成后打开新的子页面,如图其代码如下所示:
Info.openInfoDetail = function () {
if (this.check()) {
var index = layer.open({
type: 2,
title: '住房详情',
area: ['800px', '420px'], //宽高
fix: false, //不固定
maxmin: true,
content: Feng.ctxPath + '/info/info_update/' + Info.seItem.id
});
this.layerIndex = index;
}
};
当控制器接收到修改请求后,先根据选中条目id获得完整的房间信息,然后将信息注入到info_edit.html页面中,然后再返回info_edit.html页面。其代码实现如下所示:
@RequestMapping("/info_update/{infoId}")
public String infoUpdate(@PathVariable Integer infoId, Model model) {
Info info = infoService.selectById(infoId);
model.addAttribute("item",info);
if(info.getParentId()!=0)
model.addAttribute("pName", infoService.selectById(info.getParentId()).getName());
else model.addAttribute("pName","顶级");
LogObjectHolder.me().set(info);
return PREFIX + "info_edit.html";
}
info_edit.html界面如下图所示:
当修改成功后,info_info.html会收集用户更改的信息,然后向控制器发送更改请求,请求地址为/info/update其代码如下:
InfoInfoDlg.editSubmit = function() {
this.clearData();
this.collectData();
//提交信息
var ajax = new $ax(Feng.ctxPath + "/info/update", function(data){
Feng.success("修改成功!");
window.parent.Info.table.refresh();
InfoInfoDlg.close();
},function(data){
Feng.error("修改失败!" + data.responseJSON.message + "!");
});
ajax.set(this.infoInfoData);
ajax.start();
}
当控制器接收到修改请求后先找出原来的房间信息,然后查看房间名有没有被修改过,如果房间名被修改了,那此房间所有的子节点的地址都要修改,这样才能保持地址的正确性,然后使用mybatis提供的更新方法,将新数据更新到数据库中。
@RequestMapping(value = "/update")
@ResponseBody
public Object update(Info info) {
Info oldinfo=infoService.selectById(info.getRoomId());
String name=info.getName();
String oldaddress=oldinfo.getAddress();
String newaddress;
if(info.getParentId()==0)newaddress=name;
else newaddress=oldaddress.substring(0,oldaddress.length()-oldinfo.getName().length())+name;
info.setAddress(newaddress);
infoService.updateById(info);
ChangeChildAddress(newaddress,oldaddress,info.getRoomId());
return SUCCESS_TIP;
}
用户选择某一条记录,然后点击删除按钮,前端会发送一个删除请求到控制器,请求地址为/info/delete其实现代码如下所示:
Info.delete = function () {
if (this.check()) {
var ajax = new $ax(Feng.ctxPath + "/info/delete", function (data) {
Feng.success("删除成功!");
Info.table.refresh();
}, function (data) {
Feng.error("删除失败!" + data.responseJSON.message + "!");
});
ajax.set("infoId",this.seItem.id);
ajax.start();
}
};
当控制器接收到删除请求时,先通过TreeTool的removeTreeNode方法找出本房间的所有子节点,方法返回所有子节点的id与自己的id,然后通过返回的所有id删除房间信息。
@RequestMapping(value = "/delete")
@ResponseBody
public Object delete(@RequestParam Integer infoId) {
List<Integer> list= TreeTool.removeTreeNode(infoService.list(null),infoId);
for(Integer i :list)
infoService.deleteById(i);
return SUCCESS_TIP;
}
在这次的课程设计中,我花费了很多的心思与精力。只要努力就有收获,这个成品我还是比较满意的。在这个过程中,我不但对JAVA Springboot2框架和数据库有了深刻的认识和了解,同时还学会了自学与独立思考的能力。此外,在我所负责的领域中,还有几个地方考虑不足:
报修与投诉管理员回复一次默认已经解决了问题,但是实际情况可能需要管理员多次与住户进行交流才能够完全解决问题
租借流程中缺少管理员对租借的确认,如果系统分配的车位因为一些不可预知的原因不能租借,管理员不能及时反馈给用户
通知信息无法插入图片
插入信息没有控制其格式,可能会导致插入失败
我会根据上述说的不足加以改进,使系统更人性化。
[1] 王珊,数据库系统概论[M].高等教育出版社, 2014.
[2] 埃克尔,JAVA编程思想(第4版)[M].机械工业出版社, 2007.
[3] 杨开振,深入浅出SpringBoot 2.x[M].人民邮电出版社, 2019.
[4] 朱要光,SpringMVC+MyBatis开发从入门到项目实战[M].电子工业出版社, 2018.
keyboard_arrow_left上一篇 : 基于JavaEE的办公OA系统的设计与实现 基于Android-JavaEE-DB2实现的旧物交易平台 : 下一篇keyboard_arrow_right