基于SpringBoot和MySQL的社区物业管理系统
1.项目简介
1.1 介绍
基于SpringBoot+Layui的社区物业管理系统 分为业主和管理员两个角色:
- 业主
- 车位费查询
- 物业费查询
- 我的投诉列表
-
我的报修列表等功能模块
-
管理员
- 车位收费管理
- 物业收费管理
- 投诉信息管理
- 报修信息管理
- 楼宇管理
- 房屋管理
- 业主管理
- 车位管理
- 抄表管理
- 用户管理
- 报表分析等功能
1.2 技术栈
-
数据库 :MySQL 5.7.33
-
后端技术 :SpringBoot 2.3.0,MyBatisPlus
-
数据连接池 :Druid
-
前端技术 :Layui,Ajax,Json等
-
Web容器 :Apache Tomcat 8
-
项目管理工具 :Maven 3.6.0
-
版本控制工具 :Git
-
开发工具 :IDEA
2.数据库设计
2.1 表结构
building表
carcharge
clockin
clockinnew
complaint
complaint_type
house
owner
parking
property_info
property_type
records
repair
repairtype
userinfo
2.2 E-R图
3.项目实现
3.1 拦截器
java
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Userinfo userinfo= (Userinfo) request.getSession().getAttribute("user");
if(userinfo!=null){//放行
return true;
}
//如果没有登录就跳转到登录页面
response.sendRedirect(request.getContextPath()+"/login.html");
return false;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { }
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }
}
3.2 工具类
java
public class DateTimeCom {
/**
* 计算两个时间点之间的天数
*/
public static long getBetweenDay(Date jzsj) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(jzsj); //放入Date类型数据
int year=calendar.get(Calendar.YEAR); //获取年份
int month=calendar.get(Calendar.MONTH); //获取月份
int day=calendar.get(Calendar.DATE);
LocalDate start = LocalDate.of(year,month,day);
LocalDate now = LocalDate.now();
return getBetweenDay(start, now);
}
/**
* 计算两个时间点之间的天数
*/
public static long getBetweenDay(LocalDate start, LocalDate end) {
return end.toEpochDay() - start.toEpochDay();
}
/**
* 通过时间秒毫秒数判断两个时间的间隔
* @param date1 截至时间
* @param date2 当前时间
* @return
*/
public static int getBetweenDay(Date date1,Date date2)
{
int days = (int) ((date2.getTime() - date1.getTime()) / (1000*3600*24));
return days;
}
}
3.3 用代码生成器生成脚手架
3.3.1 基础信息管理部分
楼宇管理
楼宇管理主要就是显示出多少栋,多少单元,只需要building表中的属性,CRUD即可。
-
dao层 :查询所有楼宇queryBuildAll,参数numbers可以根据楼号进行查询,xml进行实现,sql语句也很简单
-
service层 :写一个分页查询所有楼宇的方法findBuildAll,实现类就调用dao层的queryBuildAll,然后new PageInfo<>(list)作为返回,这个在图书管理都经常写,简单
-
controller层 :调用service中方法findBuildAll,返回JsonObject类,类中包含code,msg,count,data四个属性,这是返回一个json对象给前端,code是成功或失败代码,msg是成功或失败信息,count是总数量,data是数据,类型是泛型T,这样的话用户表就是用户数据,学生表就是学生数据
到layuimini官网下载模板,layuimini是基于layui的后端管理系统前端模板,下载后进行修改,这个也可以参考一下博客中图书管理系统,修改主要修改url,cols中显示的字段,图书管理用到了jsp,这里不用jsp,也就是进行解耦,前端就是纯前端,增删改都做了一个封装,封装成base.js,因为增删改基本都是一样的,就是url,content不同,调用的时候传这些参数即可。还有修改功能以前jsp都是后端先查找对象,然后将对象放到作用域中,以便前端获取,这里不用jsp了,用渲染form数据的方式,实现点击修改后,就会跳出有数据的form表单,就不需要${},这种EL表达式实现。
房屋管理
同楼宇管理,略。
业主管理
实体类:实体类中除了本身的属性以外还需要一个house对象,因为显示的时候需要知道业主的房子是哪个也就是房屋编号是多少,如1-401,就是1单元401。
-
dao层**:dao层就是先写一个查询所有业主的方法queryOwnerAll,因为加入了另外一个表,我们就需要在xml实现的时候,用resultMap并继承BaseResultMap,使得业主中包含house中的id和numbers属性
-
service层、controller层**:和之前一样写分页查询所有记录即可,这个已经写过很多遍了
前端页面和之前一样增删改,房屋编号在cols数组中以下面形式添加:
java
{templet:'<div>{{d.house.numbers}}</div>',width: 100, title: '房屋编号'}
车位管理
车位管理显示的记录应该有车位号,车位是哪个业主的,即有业主姓名和业主联系电话,这就说明车位Park实体类中除了本身的属性以外,还要一个Owner业主对象
- dao层、service层、controller层 :这三层跟之前一样常规写查询所有即可,都是重复操作
前端页面改动url地址,以及在cols中以templet:方式添加业主姓名和业主电话,车位的状态1表示使用,0表示未使用,可以用一个function写,如下,以前图书管理也常见这个状态未借出和已借出,还有还书类型,有正常还书、延迟还书、破损还书、丢失还书等,都是这种形式。
抄表管理
抄表管理是一个重难点,我们来好好理一理。
实体类 :这里用另一种方式引入其他表属性,新建一个实体类RecordVo,然后继承以前的Records。
-
dao层**:先写一个查询所有抄表记录的方法queryRecordsAll,以及其实现,重点是它的xml文件中的sql
sql SELECT rec.*,hou.numbers,own.username,type.`name` as typename FROM records rec LEFT JOIN property_type type ON type.id = rec.type_id LEFT JOIN house hou ON hou.id = rec.house_id LEFT JOIN OWNER own ON own.house_id = hou.id
因为records抄表本省有type_id(费用类型:水费,电费还是其他),还有house_id,所以前端需要显示的门牌号,户主姓名(业主),费用类型都可以通过type_id和house_id这两个外键进行与owner表和house表连接,从而获取到hou.numbers(门牌号),业主姓名和费用类型 -
service层 :该层正常写查询所有即可,分页查询
-
controller层 :查询所有正常写,和之前一样操作。注意这里只要添加和删除,抄表的信息不能修改,添加叫抄表登记,我们暂且还叫添加,添加和删除过程还是相对之前内容,业务逻辑更加复杂了。先来说说添加(抄表登记),抄表登记分两步:1、添加抄表记录信息 2、添加物业收费信息 ,也就是涉及两个表。首先由于我们需要根据记录中的房子和类型查询上次抄表的度数以及相关时间信息,所以需要从dao层开始,加上方法queryByHouIdAndTypeId,倒序排列,第一个就是最后一次登记信息。查到的登记信息若非空,则获取上次的度数以及上次抄表时间,把ontime和num2更为上次度数,为空则说明没抄表过,所以上次度数做一个初始化0。然后checkTime设置当前时间,当前时间也就是checkTime。添加收费物业信息,物业信息先获取到houId,typeId,将缴费状态设置为未缴费,若抄表记录上次抄表时间为0,则ontime作为startDate,不为空则将uptime作为startDate。enddate设置为本次最新登记的时间,即ontime。下面就是计算费用类型的费用,先通过id查询到费用类型,然后获取收费标准,用(num2-num)*price就是费用,num2-num是一段时间内用的度数。money算出来后,setMoney到物业信息中,remarks同时也set,这样property_info表中所有属性都set赋值了。删除:既然添加需要涉及两个表,records和property_info,删除首先要通过id查询到需要删除的records,然后通过records获取到houseId,再获取到本次时间ontime,最后records和property_info分别调用删除方法。property_info调用的删除方法deleteInfoByHouIdAndTime需要到dao层依次实现,因为如果仅仅按照houId删除的话,有很多相同的houId会被一起删除,所以加一个参数ontime这样就唯一了
费用类型下拉框显示物业费,水费,电费,车位费这些,和图书馆里的一样动态获取费用类型数据,并渲染数据到select标签。其他都是以前常做的,复制之前的修改即可:
javascript
$.get("findAllList",{},function (data) {
var list=data;
var select=document.getElementById("typeId");
if(list!=null|| list.size()>0){
for(var obj in list){
var option=document.createElement("option");
option.setAttribute("value",list[obj].id);
option.innerText=list[obj].name;
select.appendChild(option);
}
}
form.render('select');
},"json")
管理员管理
-
dao层 :dao层由于涉及修改密码,所以需要有一个查询账号密码的方法queryUserByNameAndPwd
-
service层 :正常调用即可
-
controller层 :这里修改密码需要通过id查询到userinfo,然后判断输入的旧密码和用户的密码是否相等,相等表示输入正确,然后就可以执行新密码更新
前端页面都是写过的,复制修改即可。
3.3.2 核心业务处理模块
车位收费管理
实体类 :车位收费实体类还要加入两个属性,owner和parking,即需要知道哪个车位要收费,即车位号是多少,以及这个车位的车主叫什么
dao层,service层 :正常写
controller层: 这里查询,新增和更新需要说一说,先说查询,查询分为业主的和管理的,管理需要看到车位号,所以需要set一个numbers,而业主就只能看到自己,所以首先通过用户名查询到业主,然后获取到业主id,车位收费中set(业主id),这样业主就只能看到自己的车位信息,而不能看到其他的车主。这里初始化数据是添加一种,就是已经在使用的车位过了几个月又要缴费了,就直接初始化数据,queryParkingByStatus先查询到状态为1,也就是正在使用车位,并且该车位业主不为空,查到需要初始化的车位列表,遍历初始化。这样已经缴费的,到新的时间段初始化一下,就又需要缴费。更新操作就是缴费操作,只要将缴费状态改为1即可,setId是为了找到哪个需要更改。
前端页面 :复制修改即可,之前做过很多次了。
物业收费管理
实体类 :都是本身的属性。
-
dao层 :一个查询所有记录的方法,根据登记时间和房子id删除当前记录信息
-
service层 :service层中需要将日期格式转化成日期对应的字符串类型,也就是删除的参数ontime是string
-
controller层 :这个和车位收费管理类似,分为业主查询所有记录和管理员,管理员可能通过房屋号查询,房屋号不为空,就是特定的查询,房屋好为空就是查询所有,也就是默认的情况。业主就只能查询到自己的房屋收费情况,先通过名字获取到houId,再查询这个houId的信息。初始化操作就是跟车位收费一样,将已经存在的车主,缴新的阶段的费用,计算费用,然后设置id表示哪些需要缴费了,状态改为未缴费状态0,再进行添加,这样就是最新阶段需要缴费。更新操作就是缴费,点击缴费,成功后就会变为已缴费,也就是将status设置为1
前端页面 :这里主要讲一个这里独有的一个功能,也就是打印票据,打印票据在前端触发的事件是print,打印票据必须是同一个用户,并且是缴费状态,符合条件,就进行数据渲染,这里打印票据其实就是往表格里渲染数据,金额、用户、时间,新弹出的界面就是html写的一个表格,然后用js的方法往里面填数据,也就是数据渲染,点击打印后可以保存成pdf,也可以打印,这个了解即可
投诉信息管理
略,就只要写个查询所有记录,没啥特别的,写了很多遍了。
报修信息管理
略,一样的没啥特别的,就写个查询所有,统计报修是属于统计部分,统计简单说下,主要是到ECharts官网找到需要的图,数据传到data中,改成data需要的格式,repairMapper中写统计的方法以及实现,service和controller都直接调用即可。
3.3.3 登录部分
登录分为登录和退出,登录的LoginController中,首先创建一个HashMap,用于存键值,包括状态码,信息msg,登录时首先通过queryUserByNameAndPwd()方法到userinfo表中查询,输入的账号密码是否存在,若存在则将user对象保存至session中(session.attribute)。不存在则提示用户名或密码错。退出功能就是将session注销,即session.invalidate()。然后重定向跳转到登录页面。登录成功后,还需要配置拦截器,在com.yx包下新建一个interceptor包,一个配置类,一个拦截类。配置类中实现WebMvcConfigurer,配置拦截与不拦截信息。拦截类中,在preHandle方法中通过判断session中是否有user,进而决定放不放行。preHandle请求之前进行得调用。
3.4 主要功能代码
Java
/**
* 分页查询记录信息
*/
@RequestMapping("/queryRecordsAll")
public JsonObject queryRecordsAll(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "15") Integer limit,
RecordVo recordVo){
PageInfo <RecordVo> pageInfo=recordsService.findRecordsAll(page,limit,recordVo);
return new JsonObject(0,"ok",pageInfo.getTotal(),pageInfo.getList());
}
/**
* 抄表的添加工作
*/
@RequestMapping("/add")
@Transactional(rollbackFor = {RuntimeException.class,Error.class})
public R add(@RequestBody Records records){
/*
步骤:
1、添加抄表记录信息
1.1 根据记录中的房子和类型查询上次抄表的度数以及相关时间信息
如果存在,需要获取上次的度数,上次时间
如果不存在 上次度数设置为0 上次时间使用本次时间
1.2 添加记录信息
2、添加物业收费信息
2.1 获取 上次到这次之间的度数信息
2.2 根据收费类型查询收费标准
2.3 用1的度数×2的的收费标准 获取相关费用
2.4 并设定为未缴费状态
2.5 添加工作
*/
//根据参数房子id和类型id 获取最后一次登记信息
Integer houId=records.getHouseId();
Integer typeId=records.getTypeId();
//获取最后一次记录信息
Records rec=recordsService.queryByHouIdAndTypeId(houId,typeId);
if(rec!=null){
//获取上次表的度数 上次抄表时间
records.setUpTime(rec.getOnTime());
records.setNum(rec.getNum2());
}else{
records.setUpTime(records.getOnTime());
records.setNum(0.0);
}
//添加记录信息到数据库
records.setCheckTime(new Date());
recordsService.add(records);
//2 添加费用信息
PropertyInfo info=new PropertyInfo();
info.setHouseId(houId);
info.setTypeId(typeId);
info.setStatus(0);//未缴费
if(rec!=null){
info.setStartDate(rec.getUpTime());
}else {
info.setStartDate(records.getOnTime());
}
info.setEndDate(records.getOnTime());
//根据类型的id查询类型的费用标准
PropertyType type=propertyTypeService.findById(new Long(typeId));
double price=type.getPrice();//获取收费标准
//获取度数
double money=(records.getNum2()-records.getNum())*price;
info.setMoney(money);
info.setRemarks(records.getRemarks());
//添加记录信息
int num= propertyInfoService.add(info);
if(num>0){
return R.ok();
}else{
return R.fail("异常");
}
}
@RequestMapping("/deleteByIds")
@Transactional(rollbackFor = {RuntimeException.class,Error.class})
public R deleteByIds(String ids){
//把字符串转list集合
List<String> list=Arrays.asList(ids.split(","));
for(String id : list){
Long idLong=Long.parseLong(id);
//根据id获取对应的记录信息获取登记时间以及房子id
Records records=recordsService.findById(idLong);
//获取房子id
Integer houId=records.getHouseId();
//获取时间
Date onTime=records.getOnTime();
//删除登记表记录信息
recordsService.delete(idLong);
//物业收费信息表相关信息
propertyInfoService.deleteInfoByHouIdAndTime(houId ,onTime);
}
return R.ok();
}
}
4.项目展示
4.1 以管理员身份登录
4.2 以业主身份登录
参考文献
- 鼎祥小区物业管理系统的设计与实现(大连理工大学·芦佳)
- 基于Spring的社区信息管理系统设计与实现(华中科技大学·杨一成)
- 物业信息管理平台的设计与实现(电子科技大学·张芳)
- 基于Spring的社区信息管理系统设计与实现(华中科技大学·杨一成)
- 基于Javaweb的住宅小区物业管理系统设计与实现(江西财经大学·戴亚峰)
- 基于J2EE的物业管理系统的设计与实现(电子科技大学·贺伟)
- 基于J2EE平台的物业管理系统的设计(贵州大学·刘怡伶)
- 金华市阳光花园社区物业管理系统的设计与实现(电子科技大学·张志伟)
- 基于VF的社区物业信息管理系统的设计与实现(电子科技大学·徐玮)
- 政府物业管理系统的设计与实现(电子科技大学·郭新玉)
- 鼎祥小区物业管理系统的设计与实现(大连理工大学·芦佳)
- 小区物业管理系统的设计与实现(山东大学·王桥)
- 基于J2EE平台的物业管理系统的设计(贵州大学·刘怡伶)
- 基于Spring的社区信息管理系统设计与实现(华中科技大学·杨一成)
- 政府物业管理系统的设计与实现(电子科技大学·郭新玉)
本文内容包括但不限于文字、数据、图表及超链接等)均来源于该信息及资料的相关主题。发布者:代码港湾 ,原文地址:https://m.bishedaima.com/yuanma/35483.html