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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

centos 7.9 nginx本地化安装,把镜像改成阿里云

1.把centos7.9系统切换到阿里云的镜像源 1.1.先备份 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup1.2.下载新的CentOS-Base.repo配置文件 wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo特别…

Redux和Redux Toolkit

Redux 概念&#xff1a;redux是react最常用的集中状态管理工具&#xff0c;类似于Vue中的Pinia(vuex)&#xff0c;可以独立于框架运行作用&#xff1a;通过集中管理的方式管理应用的状态 Redux快速体验 不和任何框架绑定&#xff0c;不使用任何构建工具&#xff0c;使用纯Re…

uniapp小程序编译报错

说明 微信小程序编译每次都出现[ project.config.json 文件内容错误] project.config.json: libVersion 字段需为 string, 解决 找到manifest.json文件 添加&#xff1a;"libVersion": "latest"&#xff0c;重新编译即可。

MySQL limit N offset M 速度慢?来实际体验下

直接开始 有一张表&#xff1a;trade_user&#xff0c;表结构如下&#xff1a; mysql> desc trade_user; ------------------------------------------------------------------ | Field | Type | Null | Key | Default | Extra | -------------…

记一次IP访问MySQL失败多次被自动锁定导致无法连接问题,解决方法只需一条SQL。

&#x1f469;&#x1f3fd;‍&#x1f4bb;个人主页&#xff1a;阿木木AEcru &#x1f525; 系列专栏&#xff1a;《Docker容器化部署系列》 《Java每日面筋》 &#x1f4b9;每一次技术突破&#xff0c;都是对自我能力的挑战和超越。 前言 今天下午还在带着耳机摸鱼&#xff…

Linux CentOS 安装 MySQL 服务教程

Linux CentOS 安装 MySQL 服务教程 1. 查看系统和GNU C库(glibc)版本信息 1.1 查询机器 glibc 版本信息 glibc&#xff0c;全名GNU C Library&#xff0c;是大多数Linux发行版中使用的C库&#xff0c;为系统和应用程序提供核心的API接口。在Linux系统中&#xff0c;特别是在…

动态规划-入门理解

一、什么情况可以使用动态规划 动态规划 最优子结构 重叠子问题 转移方程 最优子结构&#xff1a;保证能从局部解推出全局解&#xff0c;也就是保证能够写出转移方程 重叠子问题&#xff1a;说明暴力解法太耗时&#xff0c;我们可以使用动态规划进行优化 转移方程&#xff…

自用---

零、环境配置 keil代码补全 keil pack包 cubemx配置安装包 一、LED cubemx配置PD2引脚为输出模式 uint16_t led_value 0x00; void led_set(uint8_t led_dis) {HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOC,led_dis<<8,GPIO_PIN_R…

03-JAVA设计模式-桥接模式

桥接模式 什么是桥接模式 桥接模式&#xff08;Bridge Pattern&#xff09;是一种将抽象与实现解耦的设计模式&#xff0c;使得二者可以独立变化。在桥接模式中&#xff0c;抽象部分与实现部分通过一个桥接接口进行连接&#xff0c;从而允许抽象部分和实现部分独立演化。 场…

服务器docker应用一览

文章目录 一、简单需求二、业务流程三、运行效果四、实现过程1. 前提2. 源码3.核心代码4. 项目打包5、部署 一、简单需求 现有某云主机服务器&#xff0c;用来做项目演示用&#xff0c;上面运行了docker应用&#xff0c;现希望有一总览页面&#xff0c;用来展示部署的应用。 …

微信小程序实现输入appid跳转其他小程序

前言 本文记录wx.navigateToMiniProgram打开另一个小程序API使用方法&#xff0c;并封装为组件。 wxml 部分 输入框用来记录appid&#xff0c;按钮用来查询并跳转。 <view class"container"><input class"input" placeholder"请输入要查…

Linux: softirq 简介

文章目录 1. 前言2. softirq 实现2.1 softirq 初始化2.1.1 注册各类 softirq 处理接口2.1.2 创建 softirq 处理线程 2.2 softirq 的 触发 和 处理2.1.1 softirq 触发2.1.2 softirq 处理2.1.2.1 在 中断上下文 处理 softirq2.1.2.2 在 ksoftirqd 内核线程上下文 处理 softirq 3.…

Facial Micro-Expression Recognition Based on DeepLocal-Holistic Network 阅读笔记

中科院王老师团队的工作&#xff0c;用于做微表情识别。 摘要&#xff1a; Toimprove the efficiency of micro-expression feature extraction,inspired by the psychological studyof attentional resource allocation for micro-expression cognition,we propose a deep loc…

HTTP与HTTPS:深度解析两种网络协议的工作原理、安全机制、性能影响与现代Web应用中的重要角色

HTTP (HyperText Transfer Protocol) 和 HTTPS (Hypertext Transfer Protocol Secure) 是互联网通信中不可或缺的两种协议&#xff0c;它们共同支撑了全球范围内的Web内容传输与交互。本文将深度解析HTTP与HTTPS的工作原理、安全机制、性能影响&#xff0c;并探讨它们在现代Web…

[leetcode]remove-duplicates-from-sorted-list-ii

. - 力扣&#xff08;LeetCode&#xff09; 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,3,4,4,5] 输出&#xff1a;[1,2,5]示例 2&…

百度OCR身份证识别C++离线SDKV3.0 C#对接

百度OCR身份证识别C离线SDKV3.0 C#对接 目录 说明 效果 问题 项目 代码 下载 说明 自己根据SDK封装了动态库&#xff0c;然后C#调用。 SDK 简介 本 SDK 适应于于 Windows 平台下的⾝份证识别系统,⽀持 C接⼜开发的 SDK,开发者可在VS2015 下⾯进⾏开发&#xff08;推荐…

爬虫+RPC+js逆向---直接获取加密值

免责声明:本文仅做技术交流与学习,请勿用于其它违法行为;如果造成不便,请及时联系... 目录 爬虫RPCjs逆向---直接获取加密值 target网址: 抓包 下断点 找到加密函数 分析参数 RPC流程 一坨: 二坨: 运行py,拿到加密值 爬虫RPCjs逆向---直接获取加密值 target网址: 优志…

Django+Celery框架自动化定时任务开发

本章介绍使用DjCelery即DjangoCelery框架开发定时任务功能&#xff0c;在Autotestplat平台上实现单一接口自动化测试脚本、业务场景接口自动化测试脚本、App自动化测试脚本、Web自动化测试脚本等任务的定时执行、调度、管理等&#xff0c;从而取代Jenkins上的定时执行脚本和发送…

R语言复现:轨迹增长模型发表二区文章 | 潜变量模型系列(2)

培训通知 Nhanes数据库数据挖掘&#xff0c;快速发表发文的利器&#xff0c;你来试试吧&#xff01;欢迎报名郑老师团队统计课程&#xff0c;4.20直播。 案例分享 2022年9月&#xff0c;中国四川大学学者在《Journal of Psychosomatic Research》&#xff08;二区&#xff0c;I…

南京航空航天大学-考研科目-513测试技术综合 高分整理内容资料-01-单片机原理及应用分层教程-单片机有关常识部分

系列文章目录 高分整理内容资料-01-单片机原理及应用分层教程-单片机有关常识部分 文章目录 系列文章目录前言总结 前言 单片机的基础内容繁杂&#xff0c;有很多同学基础不是很好&#xff0c;对一些细节也没有很好的把握。非常推荐大家去学习一下b站上的哈工大 单片机原理及…