1、项目介绍
系统功能
登录、修改密码、登出
(1)首页
(1.1)数据统计:小区人员统计对比图,占比图
(2)物业管理
(2.1)小区管理:小区数据的增删改查
(2.1.1)摄像头管理:小区摄像头数据的增删改查
(2.2)居民管理:居民数据的增删改查,居民人脸采集,Excel 数据导入,Excel 数据导出
(2.3)小区地图:所有小区在地图上的分布情况
(3)门禁管理
(3.1) 人脸识别:居民出入小区人脸识别功能
(3.2)出入记录:所有居民出入小区的人脸识别记录查询
(3.3)访客登记:访客数据的增删改查,进入登记,离开登记
(4)系统管理
(4.1)用户管理:用户数据的增删改查,给用户赋予角色设置不同的管理权限
(4.2)角色管理:角色数据的增删改查,给角色赋予权限
(4.3)菜单管理:菜单数据的增删改查,不同角色可设置不同的菜单权限
(4.4)日志管理:实时记录系统所有操作的日志,为排查问题提供依据
技术栈描述
前端:Vue+ElementUI+BaiduMap+ECharts
后端:SpringBoot+SpringMVC+MyBatisPlus+Spring Data Redis+ Swagger
第三方服务:人脸识别,腾讯AI接口(后端)
BaiduMap,ECharts(前端)
数据库:MySQL 数据库存储、Redis 缓存
其他技术:POI Excel 文件导入导出、Swagger 接口文档管理、JWT 登录认证、Spring AOP 日志管理、前端代理解决跨域问题
2、登录模块
数据表设计
用户信息表(user)
用于存储登录用户的登录信息
实现思路
①获取验证码:首先借助UUID或者其它工具生成一个符合要求的验证码;然后存入到缓存数据库redis当中,并设置超时时间;最后将验证码返回给前端
②登录验证:第一步在redis中查询验证码,验证验证码是否有效和正常 ;第二步验证用户名;第三步验证密码(JWT加密,生成token);第四步验证用户状态是否正常;第五步创建token,生成令牌,将token存入到redis中;第六步获取token的过期时间,将token和过期时间返回给前端,允许用户登录并访问首页
获取验证码
①redis配置,redis用于存储验证码和登录生成的token
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/community?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
redis:
open: true
database: 2
host: localhost
port: 6379
②导入验证码的依赖
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
<!--工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.2.4</version>
</dependency>
③获取生成验证码
@Autowired
private RedisTemplate redisTemplate;
/**
* 获取生成验证码
* @return
*/
@GetMapping("/captcha")
public Result getCaptcha(){
//1、借助UUID或者其它工具生成一个符合要求的验证码
//2、存入到缓存数据库redis当中,并设置超时时间
//3、验证码返回给前端
//利用生成验证码图片的工具类,指定宽和高,以及生成的验证码数量4
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4);
//将生成的验证码图片转成小写字符串
String code = specCaptcha.text().toLowerCase();
//通过工具类产生一个UUID值,当成验证码信息存储在redis数据库中的主键
String uuid = IdUtil.simpleUUID();
//存入redis并设置过期时间为2分钟
this.redisTemplate.opsForValue().set(uuid, code, 120, TimeUnit.SECONDS);
Map<String, String> map = new HashMap<String, String>(3);
map.put("uuid", uuid);
map.put("code", code);
//将验证码图片转成base64的图片信息,方便前端将图片解析进行显示
map.put("captcha", specCaptcha.toBase64());
//响应200,就是请求到达了控制器
return Result.ok().put("data", map);
}
登录验证
①jwt配置,jwt用于验证用户的身份和权限,生成token
jwt:
secret: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4K67DMlSPXbgG0MPp0gH
expire: 86400000
# expire: 10000
subject: door
②导入jwt依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
③jwt工具包
package com.qcby.community.util;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.UUID;
@ConfigurationProperties(prefix = "jwt")
@Component
public class JwtUtil {
private long expire;
private String secret;
private String subject;
/**
* 生成token
*
* @param userId
* @return
*/
public String createToken(String userId) {
String token = Jwts.builder()
//载荷:自定义信息
.claim("userId", userId)
//载荷:默认信息
.setSubject(subject) //令牌主题
.setExpiration(new Date(System.currentTimeMillis() + expire)) //过期时间
.setId(UUID.randomUUID().toString())
//签名哈希
.signWith(SignatureAlgorithm.HS256, secret)
//组装jwt字符串
.compact();
return token;
}
//Token校验
public boolean checkToken(String token){
if(StringUtils.isEmpty(token)){
return false;
}
try {
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
} catch (Exception e) {
return false;
}
return true;
}
public long getExpire() {
return expire;
}
public void setExpire(long expire) {
this.expire = expire;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
}
④登录请求处理
@Autowired
private JwtUtil jwtUtil;
/**
* 前端发送过来的登录请求
* @param loginForm
* @param session
* @return
*/
@PostMapping("/login")
public Result login(@RequestBody LoginForm loginForm, HttpSession session){
//1、查询redis验证,验证码是否有效和正常
//2、验证用户名
//3、验证密码(JWT加密,生成token)
//4、验证用户状态是否正常
//5、允许用户登录并访问首页
//验证码校验
String code = (String) this.redisTemplate.opsForValue().get(loginForm.getUuid());
//判断验证码是否有效
if(code == null){
// return Result.error("验证码已过期");
return Result.ok().put("status", "fail").put("date", "验证码已过期");
}
//判断验证码是否正确
if(!code.equals(loginForm.getCaptcha())){
// return Result.error("验证码错误");
return Result.ok().put("status", "fail").put("date", "验证码错误");
}
//判断用户名是否正确
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", loginForm.getUsername());
User user = this.userService.getOne(queryWrapper);
if(user == null){
return Result.error("用户名错误");
}
//判断密码是否正确,密码加密之后比对
String password = SecureUtil.sha256(loginForm.getPassword());
if(!password.equals(user.getPassword())){
return Result.error("密码错误");
}
//验证用户是否可用
if(user.getStatus() == 0) {
return Result.error("账号已被锁定,请联系管理员");
}
//登录成功
session.setAttribute("user", user);
//创建token,生成令牌
String token = this.jwtUtil.createToken(String.valueOf(user.getUserId()));
//将token存入redis,每一次访问不需要重复登录,直接验证令牌
this.redisTemplate.opsForValue().set("communityuser-"+user.getUserId(), token,jwtUtil.getExpire());
Map<String,Object> map = new HashMap<>();
map.put("token", token);
map.put("expire", jwtUtil.getExpire());
// LogAspect.user = user;
return Result.ok().put("data", map);
}
界面
3、修改密码
实现思路
①发送更新密码请求,弹出更新密码弹出层
②前端密码格式验证,新旧密码是否一致验证
③修改密码:第一步获取session中的用户信息;第二步将根据用户查询的密码和前端传来的旧密码进行比较,如果相等,将新密码加密后在数据库中更新密码字段信息,密码更新成功,返回。
修改密码请求处理
/**
* 修改密码
* @return
*/
@PutMapping("/updatePassword")
public Result updatePassword(@RequestBody UpdatePasswordForm updatePasswordForm, HttpSession session){
User user = (User)session.getAttribute("user");
String pwd = user.getPassword();
String password = SecureUtil.sha256(updatePasswordForm.getPassword());
if(pwd.equals(password)){
String newpassword = SecureUtil.sha256(updatePasswordForm.getNewPassword());
user.setPassword(newpassword);
if(userService.updateById(user)){
return Result.ok().put("status","success");
}
return Result.error("更新密码失败");
}
return Result.ok().put("status","passwordError");
}
界面
4、登出模块
实现思路
①登出请求:将当前session设置为无效
②将token设置为空
③将router设置为空
④将cookie里面的token信息清空
⑤返回登录页面
登出请求处理
/**
* 用户退出
* @param session
* @return
*/
@PostMapping("/logout")
public Result logOut(HttpSession session){
session.invalidate();
return Result.ok();
}
5、首页
登录成功后,根据当前的登录用户来动态加载对应的菜单列表(路由),显示该用户能访问的菜单;并且同时查看小区数据统计,通过柱状图和饼状图展示
数据表设计
角色表(role)
用于存储用户的角色信息
用户角色关联表(user_role)
用户存储角色和用户的关联信息
菜单表(menu)
用于存储前端展示的菜单信息,其中parent_id代表父级菜单的序号,0代表一级菜单,name代表菜单名称,path代表菜单url,component代表组件路径,icon代表组件图标
角色菜单关联表(role_menu)
用于存储角色拥有的菜单权限信息
小区信息表(community)
用户存储小区信息,其中term_count代表楼栋数量,seq代表排序,lng和lat分别代表经度和纬度
住户表(person)
存储小区的住户信息,其中state代表人脸录入状态,2代表已录入,1代表未录入
加载动态路由
实现思路
①通过session获取用户信息
②根据userId获取角色名称,需要在user_role表和role表中联表查询
③根据userId获取用户的权限菜单:
第一步:根据用户的id查询该用户所对应的角色以及该角色所对应的菜单,需要user_role、user_menu、menu三个表联表查询;
第二步:按照查询出来的菜单进行封装,一个一级菜单的信息封装进一个列表,此菜单下的二级菜单的信息封装进此列表的子列表中,若有三级菜单以此类推进行封装
④返回用户信息、角色名称和用户的权限菜单信息,格式如下
"data": {
"userId": 1,
"username": "admin",
"password": "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92",
"userType": 1,
"realName": "管理员",
"contact": "",
"mobile": "15679711120",
"status": 1,
"roleIdList": null
},
"roles": "超级管理员",
"routers": [
{
"name": "系统管理",
"path": "/sys",
"hidden": "false",
"redirect": "noRedirect",
"component": "Layout",
"alwaysShow": true,
"meta": {
"title": "系统管理",
"icon": "system"
},
"children": [
{
"name": "管理员管理",
"path": "/user",
"hidden": "false",
"component": "sys/user/index",
"meta": {
"title": "管理员管理",
"icon": "user"
}
}
]
}
]
封装返回的routers信息MenuRouterVO
@Data
public class MenuRouterVO {
private String name;
private String path;
private String component;
private String hidden;
private String redirect = "noRedirect";
private Boolean alwaysShow = true;
private MetaVO meta;
private List<ChildMenuRouterVO> children;
}
@Data
public class ChildMenuRouterVO {
private String name;
private String path;
private String component;
private String hidden;
private MetaVO meta;
}
@Data
public class MetaVO {
private String title;
private String icon;
}
加载动态路由controller请求
/**
* 通过登录的用于加载动态路由
* 显示该用户能访问的菜单
* @param session
* @return
*/
@GetMapping("/getRouters")
public Result getRouters(HttpSession session){
//获取用户名称
User user = (User)session.getAttribute("user");
//获取用户的角色名称
String roles = roleMapper.getRoleNameByUserId(user.getUserId());
//获取用户的权限菜单
List<MenuRouterVO> routers = this.menuService.getMenuRouterByUserId(user.getUserId());
return Result.ok()
.put("data", user)
.put("roles", roles)
.put("routers",routers);
}
获取用户的角色名称的mapper
//根据userId获取角色名称
@Select("SELECT role_name FROM role, user_role where user_role.role_id=role.role_id and user_role.user_id=#{userId}")
public String getRoleNameByUserId(Integer userId);
获取用户的菜单信息service
@Autowired
private MenuMapper menuMapper;
@Override
public List<MenuRouterVO> getMenuRouterByUserId(Integer userId) {
//1.根据用户的id查询该用所对应的角色以及该角色所对应的菜单
List<Menu> menuList = this.menuMapper.getMenusByUserId(userId);
//2.创建一个集合List<MenuRouterVO> 最终的集合
List<MenuRouterVO> list = new ArrayList<>();
//3.遍历该用户所能查看的所有菜单找到一级菜单封装进MenuRouterVO
for (Menu menu : menuList) {
//挑选出父级菜单
if (menu.getParentId() == 0) {
MenuRouterVO menuRouterVO = new MenuRouterVO();
//给父级菜单对象赋值,bean实体类的封装工具类,框架提供
//将源对象menu中的相同属性赋值给新对象menuRouterVO
BeanUtils.copyProperties(menu, menuRouterVO);
//再将没有的属性进行赋值
MetaVO metaVO = new MetaVO();
metaVO.setTitle(menu.getName());
metaVO.setIcon(menu.getIcon());
menuRouterVO.setMeta(metaVO);
//生成children
Integer menuId = menu.getMenuId();
//4.不是一级菜单的继续遍历找到属于哪个一级菜单下挂在该菜单下
List<ChildMenuRouterVO> children = new ArrayList<>();
for (Menu child : menuList) {
if(child.getParentId() == menuId){
//5.封装子菜单ChildMenuRouterVO 在放进集合List<ChildMenuRouterVO>
ChildMenuRouterVO childVO = new ChildMenuRouterVO();
BeanUtils.copyProperties(child, childVO);
MetaVO childMetaVO = new MetaVO();
childMetaVO.setTitle(child.getName());
childMetaVO.setIcon(child.getIcon());
childVO.setMeta(childMetaVO);
children.add(childVO);
}
}
//6.将子菜单集合挂在MenuRouterVO的children的集合属性下
menuRouterVO.setChildren(children);
//7.将每一个MenuRouterVO放进大集合
list.add(menuRouterVO);
}
}
return list;
}
获取用户的菜单信息mapper
@Repository
public interface MenuMapper extends BaseMapper<Menu> {
@Select({
"select m.menu_id,m.parent_id,m.name,m.path,m.component," +
"m.menu_type,m.status,m.icon,m.sort,m.hidden from " +
"user_role ur,role_menu rm,menu m where ur.role_id = rm.role_id" +
" and rm.menu_id = m.menu_id " +
"and ur.user_id = #{userId} order by m.sort"
})
public List<Menu> getMenusByUserId(Integer userId);
}
查看小区数据统计
实现思路
查询出所有的小区名称,以及每个小区的对应的住户数量,并将小区名称与其对应的住户数量封装成单个list,从小区信息表community和住户表person中联表查询出来,返回数据如下所示:
"data": {
"names": [
"栖海澐颂",
"宸悦国际",
"流星花园二区",
"农学院家属院",
"金达园",
"建发城建·文源府",
"北清云际"
],
"nums": [
5,
3,
1,
2,
4,
2,
1
],
"list":[
{
"name": "栖海澐颂",
value: 5
}
]
echarts安装
cnpm install echarts@4.9.0 --save
前端代码
drawLine(){
chart().then(res => {
// 基于准备好的dom,初始化echarts实例
let myChart = this.$echarts.init(document.getElementById('myChart'))
// 绘制图表
myChart.setOption({
color: ['#3398DB'],
title: {
text: '智慧社区住户量统计',
subtext: '对比图',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
data: res.data.names
},
yAxis: {},
series: [{
name: '住户量',
type: 'bar',
data: res.data.nums
}],
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200;
}
});
let myChart2 = this.$echarts.init(document.getElementById('myChart2'))
myChart2.setOption({
title: {
text: '智慧社区住户量统计',
subtext: '占比图',
left: 'center'
},
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
visualMap: {
show: false,
min: 80,
max: 600,
inRange: {
colorLightness: [0, 1]
}
},
series: [
{
name: '住户量',
type: 'pie',
radius: '55%',
center: ['50%', '50%'],
data: res.data.list.sort(function (a, b) { return a.value - b.value; }),
roseType: 'radius',
itemStyle: {
color: '#3398DB'
},
animationType: 'scale',
animationEasing: 'elasticOut',
animationDelay: function (idx) {
return Math.random() * 200;
}
}
]
});
});
}
chartVO数据封装
@Data
public class ChartVO {
private Integer value;
private String name;
}
查看小区数据统计controller请求
/**
* 查看小区数据统计
* @return
*/
@GetMapping("/chart")
public Result chart(){
Map map = this.inOutRecordService.chart();
return Result.ok().put("data", map);
}
查看小区数据统计service
@Autowired
private InOutRecordMapper inOutRecordMapper;
@Override
public Map chart() {
Map<String, List> map = new HashMap<>();
List<String> names = new ArrayList<>();
List<Integer> nums = new ArrayList<>();
List<ChartVO> chartVOList = inOutRecordMapper.chart();
List<ChartVO> list = new ArrayList<>();
for(ChartVO chartVo: chartVOList){
names.add(chartVo.getName());
nums.add(chartVo.getValue());
list.add(chartVo);
}
map.put("names",names);
map.put("nums",nums);
map.put("list",list);
return map;
}
查看小区数据统计mapper
@Select("select count(*) value, c.community_name name from community c, person p where p.community_id=c.community_id group by c.community_id")
List<ChartVO> chart();
界面
6、代码生成器
生成代码
生成entity、mapper、mapper.xml、service、serviceImpl、controller文件
package com.qcby.community;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String[] args) {
AutoGenerator autoGenerator = new AutoGenerator();
DataSourceConfig dataSourceConfig = new DataSourceConfig();
dataSourceConfig.setDbType(DbType.MYSQL);
dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
dataSourceConfig.setUsername("root");
dataSourceConfig.setPassword("123456");
dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/community?useUnicode=true&characterEncoding=UTF-8");
autoGenerator.setDataSource(dataSourceConfig);
GlobalConfig globalConfig = new GlobalConfig();
globalConfig.setOpen(false);
globalConfig.setOutputDir(System.getProperty("user.dir")+"/src/main/java");
globalConfig.setAuthor("admin");
globalConfig.setServiceName("%sService");
autoGenerator.setGlobalConfig(globalConfig);
PackageConfig packageConfig = new PackageConfig();
packageConfig.setParent("com.qcby.community");
packageConfig.setEntity("entity");
packageConfig.setMapper("mapper");
packageConfig.setController("controller");
packageConfig.setService("service");
packageConfig.setServiceImpl("service.impl");
autoGenerator.setPackageInfo(packageConfig);
StrategyConfig strategyConfig = new StrategyConfig();
strategyConfig.setEntityLombokModel(true);
strategyConfig.setNaming(NamingStrategy.underline_to_camel);
strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
strategyConfig.setInclude("community");
TableFill tableFill1 = new TableFill("create_time", FieldFill.INSERT);
List<TableFill> list = Arrays.asList(tableFill1);
strategyConfig.setTableFillList(list);
autoGenerator.setStrategy(strategyConfig);
autoGenerator.execute();
}
}
生成示例,以community为例
entity
package com.qcby.community.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
*
* </p>
*
* @author admin
* @since 2024-03-26
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class Community implements Serializable {
private static final long serialVersionUID=1L;
@TableId(value = "community_id", type = IdType.AUTO)
private Integer communityId;
/**
* 小区名称
*/
private String communityName;
/**
* 楼栋数量
*/
private Integer termCount;
/**
* 序号
*/
private Integer seq;
/**
* 创建人
*/
private String creater;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 经度
*/
private Float lng;
/**
* 维度
*/
private Float lat;
}
mapper
package com.qcby.community.mapper;
import com.qcby.community.entity.Community;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* <p>
* Mapper 接口
* </p>
*
* @author admin
* @since 2024-03-26
*/
public interface CommunityMapper extends BaseMapper<Community> {
}
mapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qcby.community.mapper.CommunityMapper">
</mapper>
service
package com.qcby.community.service;
import com.qcby.community.entity.Community;
import com.baomidou.mybatisplus.extension.service.IService;
import com.qcby.community.form.CommunityListForm;
import com.qcby.community.vo.PageVO;
/**
* <p>
* 服务类
* </p>
*
* @author admin
* @since 2024-03-26
*/
public interface CommunityService extends IService<Community> {
}
serviceImpl
package com.qcby.community.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qcby.community.entity.Community;
import com.qcby.community.form.CommunityListForm;
import com.qcby.community.mapper.CommunityMapper;
import com.qcby.community.mapper.PersonMapper;
import com.qcby.community.service.CommunityService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcby.community.vo.CommunityVO;
import com.qcby.community.vo.PageVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
/**
* <p>
* 服务实现类
* </p>
*
* @author admin
* @since 2024-03-26
*/
@Service
public class CommunityServiceImpl extends ServiceImpl<CommunityMapper, Community> implements CommunityService {
}
controller
package com.qcby.community.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.stereotype.Controller;
/**
* <p>
* 前端控制器
* </p>
*
* @author admin
* @since 2024-03-26
*/
@Controller
@RequestMapping("//community")
public class CommunityController {
}
7、返回封装结果Result
此系统所有的结果都是返回json格式,统一返回样式如下,因此进行返回结果集的统一封装
{
"msg": "操作成功",
"code": 200// 其它数据
}
代码如下:
package com.qcby.community.util;
import java.util.HashMap;
public class Result extends HashMap<String,Object> {
public static Result ok(){
Result result = new Result();
result.put("code", 200);
result.put("msg", "操作成功");
return result;
}
public static Result error(String msg){
Result result = new Result();
result.put("code", 500);
result.put("msg", msg);
return result;
}
@Override
public Result put(String key, Object value) {
super.put(key, value);
return this;
}
}