实战项目——智慧社区(一)

news2025/6/21 23:40:29

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;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1584814.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Cesium学习笔记】二、隐藏控件及按钮

【Cesium学习笔记】二、隐藏控件及按钮 一、隐藏控件二、隐藏cesium图标 Ps:本教程所有代码于同一个工程中&#xff0c;运行npm run dev默认首页为App.vue&#xff0c;只需替换App.vue的内容即可切换不同页面。 将上一节的App.vue保存为类似“加载cesium.vue”这种对应名称。 …

回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测

回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测 目录 回归预测 | Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 Matlab实现WOA-GPR鲸鱼算法优化高斯过程回归多变量回归预测 1.Matlab实现…

解决Android Studio Loading Devices问题

目录 一、解决办法&#xff08;普通&#xff09;&#xff1a; 二、解决办法的优化 三、解决办法的进一步优化 问题&#xff1a;windows 11 电脑&#xff0c;每次开机&#xff0c;打开Android Studio,都会显示Loading Devices&#xff0c;连接不上设备。 原因&#xff1a;adb…

SpringBoot和Vue2项目配置https协议

1、SpringBoot项目 ① 去你自己的云申请并下载好相关文件&#xff0c;SpringBoot下载的是Tomcat&#xff08;默认&#xff09;&#xff0c;Vue2下载的是Nginx ② 将下载的压缩包里面的.pfx后缀文件拷贝到项目的resources目录下 ③ 编辑配置文件 &#xff08;主要是框里面的内…

SOCKS代理是如何提高网络性能和兼容性的?

SOCKS代理作为一种网络协议中间件&#xff0c;不仅在提升网络隐私和安全性方面发挥着重要作用&#xff0c;也在提高网络性能和兼容性方面有着不容忽视的影响&#x1f680;。本文将深入探讨SOCKS代理如何通过减少网络延迟&#x1f680;、优化数据传输&#x1f504;、提高跨平台兼…

MacOS下Qt 5开发环境安装与配置

最近笔者在MacOS中使用Qt Creator开发Qt程序时遇到了一些问题&#xff0c;在网上查了不少资料&#xff0c;都没有找到解决方案&#xff0c;只有自己进行研究摸索了&#xff0c;今天晚上终于将目前遇到的问题全部解决了&#xff0c;特记录下来分享给大家。 笔者使用的是MacOS 1…

政安晨:【深度学习神经网络基础】(六)—— 前馈神经网络

目录 简述 前馈神经网络结构 计算输出 初始化权重 径向基函数神经网络 径向基函数 政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 政安晨的机器学习笔记 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎…

“反正你又看不到,少写一行又何妨......”

单链表专题 1.链表的概念及结构2. 实现单链表3. 链表的分类 1.链表的概念及结构 概念&#xff1a;链表是⼀种物理存储结构上⾮连续、⾮顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。 链表的结构跟火车车厢相似&#xff0c;淡季时⻋次的⻋厢…

跨平台桌面应用 Electron 入门学习

本文章主要为该视频的学习笔记&#xff0c;如果侵权会速删。 Electron 01 课程介绍_哔哩哔哩_bilibiliElectron 01 课程介绍, 视频播放量 3046、弹幕量 0、点赞数 75、投硬币枚数 43、收藏人数 179、转发人数 2, 视频作者 极客丶张德龙, 作者简介 当你的能力还不足以撑起自己的…

2024-04-10 Linux gzip 和 gunzip 命令,gzip 压缩的文件通常比原始文件小得多。

一、gzip 是 Linux 系统中用于压缩文件的命令&#xff0c;它通常用于将单个文件压缩成 .gz 格式的文件。gzip 压缩的文件通常比原始文件小得多&#xff0c;因此它在节省磁盘空间和减少文件传输时间方面非常有用。 gzip 命令的基本语法如下&#xff1a; gzip [选项] [文件]复制…

实现自动打包py及替换pyinstaller --add-data参数的方法

2024年了&#xff0c;PyInstaller已经来到了6.5.0版本&#xff0c;可我还是不会用它那个--add-data的方法&#xff0c;度了几圈试了试&#xff0c;始终不&#xff08;行&#xff09;如&#xff08;不&#xff09;意&#xff08;通&#xff09;&#xff0c;就是没能把附加文件&a…

Dubbo 序列化

Dubbo 序列化 1、什么是序列化和反序列化 序列化&#xff08;serialization&#xff09;在计算机科学的资料处理中&#xff0c;是指将数据结构或对象状态转换成可取用格式&#xff08;例如存成文件&#xff0c;存于缓冲&#xff0c;或经由网络中发送&#xff09;&#xff0c;…

Redis中的集群(五)

集群 在集群中执行命令 MOVED错误。 当节点发现键所在的槽并非由自己负责处理的时候&#xff0c;节点就会向客户端返回一个MOVED错误&#xff0c;指引客户端转向至正在负责槽的节点&#xff0c;MOVED错误的格式为: MOVED <slot> <ip>:<port>其中slot为键…

软件建模与设计 —— 入门

序言 对于软件建模与设计&#xff0c;非科班出身的同学可能和我一样比较陌生&#xff0c;虽然日常开发中也涉及到建模&#xff0c;但是并没有系统的学习过软件建模设计。类似于设计模式&#xff0c;软件建模与设计也有一套三板斧。 设计模式 创建型模式提供了创建对象的机制…

ZYNQ7000 PL与PS交互总结

这里写目录标题 一、ZYNQ7000整体框架二、AXI总线与接口2.1 AXI总线协议分类2.1.1 AXI_Lite协议2.1.2 AXI_Full协议2.1.3 AXI_Stream协议 2.2 AXI接口分类 三、PS与PL交互方式总结3.1 PL中断3.2 AXI_Lite协议配合AXI GP接口进行寄存器访问3.3 AXI_Full协议配合AXI HP接口进行内…

解决苹果iMac的M1芯片Node Sass does not yet support your current environment的问题

问题背景 如图所示&#xff0c;这是我的电脑&#xff0c;M1芯片 启动前端项目老是报错&#xff0c;说node Sass不支持我当前的环境&#xff0c;同事的macBook是intel芯片的&#xff0c;就能跑起项目来 很烦 但是不慌&#xff01;&#xff01;&#xff01; 咱有解决方法啦&a…

添加okHttp依赖报错

compile "com.squareup.okhttp:okhttp:2.4.0" compile com.squareup.okio:okio:1.5.0 compile "com.google.code.gson:gson:2.8.0" 升级了&#xff0c;改为 implementation "com.squareup.okhttp:okhttp:2.4.0"implementation com.squareup.o…

零基础入行IT行业:AI助力实现梦想

目录 一、前言 二、学习路径&#xff1a;构建你的“AI学习阶梯” 1.基础知识启蒙&#xff08;预期时间&#xff1a;1-2个月&#xff09; 2.技能逐层提升&#xff08;预期时间&#xff1a;3-6个月&#xff09; 3.深化专业方向&#xff08;预期时间&#xff1a;6-12个月&…

浏览器的重排重绘

相关问题 如何提升页面渲染性能如何减少页面重排重绘哪些行为会引起重排/重绘 关键点 渲染性能 Layout Paint 浏览器渲染大致分为四个阶段&#xff0c;其中在解析 HTML 后&#xff0c;会依次进入 Layout 和 Paint 阶段。样式或节点的更改&#xff0c;以及对布局信息的访问等…

Node.js 的 5 个常见服务器漏洞

Node.js 是一个强大且广泛使用的 JavaScript 运行时环境&#xff0c;用于构建服务器端应用程序。然而&#xff0c;与任何其他软件一样&#xff0c;Node.js 也有自己的一些漏洞&#xff0c;如果处理不当&#xff0c;可能会导致安全问题。请注意&#xff0c;这些漏洞并不是 Node.…