人脸考勤签到基础篇

news2024/12/23 15:19:53

目录

创建小程序底部Tab导航

开通腾讯云对象存储服务

一、静态资源要放在网上

二、为什么不选择阿里云或者华为云的对象存储服务?

二、开通腾讯云对象存储服务

三、存储静态资源

设计首页的英雄区和栏目导航

设计人脸签到页面

实现签到自拍功能

缓存系统常量数据

一、Emos系统的常量数据

二、读取常量数据

封装检测当天是否可以签到(持久层)

一、为什么要检测是否可以签到?

二、封装持久层代码

封装检测当天是否可以签到(业务层) 

封装检测当天是否可以签到(Web层)

实现Shiro认证功能

一、认证与授权执行流程

二、查询用户信息

二、实现认证方法

实现Shiro 授权功能

一、实现授权方法

二、添加权限验证注解


创建小程序底部Tab导航

        ……

开通腾讯云对象存储服务

一、静态资源要放在网上

        微信小程序打包发布有体积限制,不能超过2M,分包加载最多不能超过8M。正因为小程序有体积限制,所以我们不能往小程序项目中放置太多的静态资源,比如体积超大的图片。我们应该尽可能的把静态资源放在网上,然后在小程序页面上引用这些静态资源。 

        网上有很多图床可以使用,这里我选择腾讯云的对象存储服务当做图床。腾讯云的对象存储服务可以免费试用6个月,并且为个人提供50GB的免费空间。即便试用结束,腾讯云的对象存储价格也不贵。10G资源包,1个月的价格仅仅0.85元。对于普通的开发者来说,10G的存储空间足够了。

二、为什么不选择阿里云或者华为云的对象存储服务?

        华为云的服务器大部分是ARM架构的,对很多Linux程序包的兼容性不好,导致我们无法正 常部署和运行程序,所以你在选择华为云的时候一定要慎重,先了解清楚,别盲目上车。

        阿里云的问题是超售严重,假设1台硬件服务器能运行200个虚拟云主机,但是阿里偏偏一 台主机跑2000个虚拟云主机,最大程度榨取硬件主机的商业价值。当硬件服务器中运行的 云主机过多,最先体现出来的是硬盘IO能力的下降。因为硬盘IO本来就比内存IO慢很多, 加之云主机共享使用硬盘IO,这就导致某个云主机分得的硬盘IO速度非常有限。

        比方说, 你在阿里云主机上面安装MySQL数据库,执行一个非常简单的SQL语句,都要登上7~10秒 钟才能获得结果,这种超慢的读写速度真让人抓狂。也许有人想说,干嘛在云主机上面安 装MySQL,直接购买数据库服务不就行了么?还真不行,运营商提供的数据库服务,最多 带了主从同步这种数据弱一致的集群方案,你想要数据强一致性的数据库集群,只能在云 主机里面自己安装。因此不是购买运营商的数据库服务就一了百了的。

        腾讯云的超售不严重,每个云主机的IO性能跟本地主机差不多。我在腾讯云主机上面安装MySQL数据库,执行SQL语句,几十毫秒就得到了结果,几乎跟本地执行SQL是同样的速度,所以我们单位 的所有产品都是部署在腾讯云上面。 

二、开通腾讯云对象存储服务

        用浏览器访问腾讯云对象存储服务的主页,根据提示开通服务即可,非常的简单。

三、存储静态资源

        首先我们要创建一个存储桶,然后才能上传静态文件。 

        有了存储桶之后,我们就可以上传各种静态文件了,比如说我们要做轮播焦点图,那么就可以把这些图片预先上传到腾讯云上面。

设计首页的英雄区和栏目导航

        ……

设计人脸签到页面

        ……

实现签到自拍功能

        ……

缓存系统常量数据

        编写SpringBoot初始化方法(SpringBoot项目启动之后,自动执行的方法)。和Java基础里面的静态语句块非常的类似。没错,静态语句块也能实现项目的初始化,但是,静态语句块没法接受SpringBoot项目注入的各种关系,还有一些值。所以我们选择SpringBoot的初始化方法,可以正常接收到 注入的各种关系,引用,值注入。

@PostConstruct
init()

一、Emos系统的常量数据

        在 sys_config 数据表中保存了Emos系统的常量配置信息,其中就包括了考勤部分的常量信息。例如每天上班考勤从几点开始,截止到几点。下班考勤从几点开始,几点结束。 

 

        因为这些常量信息跟考勤模块息息相关,所以我们要编写Java代码,在SpringBoot项目启动的时候,就去数据库读取这些常量信息,然后缓存成Java对象,全局都可以使用。

二、读取常量数据

在 SysConfigDao.xml 文件中声明查询语句 

<select id="selectAllParam" resultType="com.example.emos.wx.db.pojo.SysConfig"> 
    SELECT param_key, param_value FROM sys_config WHERE status = 1;
</select>

在 SysConfigDao.java 中声明抽象方法 

@Mapper
public interface SysConfigDao { 
    public List<SysConfig> selectAllParam();
} 

在 com.example.emos.wx.config 中创建 SystemConstants.java 常量封装类

@Data
@Component
public class SystemConstants { 
    public String attendanceStartTime; 
    public String attendanceTime;
    public String attendanceEndTime; 
    public String closingStartTime; 
    public String closingTime; 
    public String closingEndTime;
}

在 EmosWxApiApplication.java 文件中创建 init() 方法,读取常量数据并缓存

@SpringBootApplication
@ServletComponentScan
@Slf4j
public class EmosWxApiApplication { 

    @Autowired
    private SysConfigDao sysConfigDao; 

    @Autowired
    private SystemConstants constants; 

    public static void main(String[] args) {
        SpringApplication.run(EmosWxApiApplication.class, args);
    }

    @PostConstruct
    public void init() {
        List<SysConfig> list = sysConfigDao.selectAllParam();
        list.forEach(one -> {
            String key = one.getParamKey();
            key = StrUtil.toCamelCase(key);
            String value = one.getParamValue();
            try {
                Field field = constants.getClass().getDeclaredField(key);
                field.set(constants, value);
            } catch (Exception e) {
                log.error("执行异常", e);
            }
        });
    }
}

封装检测当天是否可以签到(持久层)

一、为什么要检测是否可以签到?

        上节课我们通过分装Emos系统常量信息,从而得知考勤是分为起止时间的。在考勤开始之前,用户是不能考勤签到的。同理,在当天考勤结束之后,用户也是不能考勤签到的。甚至节假日也不能考勤,只有正常的工作日才能考勤签到。 

怎么判断当天是工作日还是节假日? 

在数据库中有 tb_workday 和 tb_holidays 两张数据表,记录着哪天是工作日,哪天是休息日。 

        Emos系统默认周一至周五为工作日,周六周日为休息日。但是这两张表不是把所有的工作日和休息日都记录下来,只是记录比特殊的工作日或者休息日。比如说今年的中秋节赶上了礼拜四,于是就把周五和周六设置成休息日,跟中秋节连成三连休,然后周日正常上班。这种特殊情况我们就要记录下来。在 tb_workday 记录周日是工作日,在 tb_holidays 表中记录周五那天是休息日。这样Emos系统在中秋三连休期间不会执行考勤签到。

二、封装持久层代码

查询特殊休息日 

在 TbHolidaysDao.xml 文件中,添加查询语句 

<select id="searchTodayIsHolidays" resultType="Integer"> 
    SELECT id FROM tb_holidays WHERE date=CURRENT_DATE LIMIT 1;
</select>

在 TbHolidaysDao.java 文件中,添加抽象方法 

@Mapper
public interface TbHolidaysDao { 
    public Integer searchTodayIsHolidays();
} 

查询特殊工作日 

在 TbWorkdayDao.xml 文件中,添加查询语句 

<select id="searchTodayIsWorkday" resultType="Integer"> 
    SELECT id FROM tb_workday WHERE date=CURRENT_DATE LIMIT 1;
</select>

在 TbWorkdayDao.java 文件中,添加抽象方法

@Mapper
public interface TbWorkdayDao { 
    public Integer searchTodayIsWorkday();
}

查询当天是否已经签到

        tb_checkin 表结构如下,Emos不仅要记录考勤的人员、时间,还要记录考勤人的地理坐标,然后根据疫情实时信息,判定用户所处的地区是新冠疫情的高危地区还是低风险地区。这部分功能,后续的章节我们再实现。 

 

在 TbCheckinDao.xml 文件中,添加查询语句

<select id="haveCheckin" parameterType="HashMap" resultType="Integer"> 
    SELECT id
    FROM tb_checkin
    WHERE user_id = #{userId} AND date = CURRENT_DATE
    AND create_time BETWEEN #{start} AND #{end}
    LIMIT 1;
</select>

在 TbCheckinDao.java 文件中,添加抽象方法 

@Mapper
public interface TbCheckinDao { 
    public Integer haveCheckin(HashMap param);
}

封装检测当天是否可以签到(业务层) 

        service类将来有发送邮件的功能,邮件发送比较耗时,所以想设计成异步的。线程的异步执行就需要把service类定义为多例的@Scope("prototype")。不可以是单例的,没办法走线程的异步执行。

        DateUtil是HuTool库里自带的工具类,库里的date()可以创建一个当前的日期对象。这个日期对象类型不是Date类型,是DateTime类型。DateTime是HuTool自定义的一个Java类,是Date的子类,但是增添了更多的实用方法。

在 com.example.emos.wx.service 包中,创建 CheckinService 接口

public interface CheckinService { 
    public String validCanCheckIn(int userId, String date);
} 

在 com.example.emos.wx.service.impl 包中,创建 CheckinServiceImpl 实现类

@Service
@Scope("prototype") 
@Slf4j
public class CheckinServiceImpl implements CheckinService { 

    @Autowired
    private SystemConstants systemConstants; 

    @Autowired
    private TbHolidaysDao holidaysDao; 

    @Autowired
    private TbWorkdayDao workdayDao;

    @Autowired
    private TbCheckinDao checkinDao;

    @Override
    public String validCanCheckIn(int userId, String date) {

        boolean bool_1 = holidaysDao.searchTodayIsHolidays() != null ? true : false;
        boolean bool_2 = workdayDao.searchTodayIsWorkday() != null ? true : false;
        String type = "工作日";
        if (DateUtil.date().isWeekend()) {
            type = "节假日";
        }

        if (bool_1) {
            type = "节假日";
        } else if (bool_2) {
            type = "工作日";
        }
        if (type.equals("节假日")) {
            return "节假日不需要考勤";
        } else {
            DateTime now = DateUtil.date();
            String start = DateUtil.today() + " " + systemConstants.attendanceStartTime;
            String end = DateUtil.today() + " " + systemConstants.attendanceEndTime;
            DateTime attendanceStart = DateUtil.parse(start);
            DateTime attendanceEnd = DateUtil.parse(end);
            if (now.isBefore(attendanceStart)) {
                return "没有到上班考勤开始时间";
            } else if (now.isAfter(attendanceEnd)) {
                return "超过了上班考勤结束时间";
            } else {
                HashMap map = new HashMap();
                map.put("userId", userId);
                map.put("date", date);
                map.put("start", start);
                map.put("end", end);
                boolean bool = checkinDao.haveCheckin(map) != null ? true : false;
                return bool ? "今日已经考勤,不用重复考勤" : "可以考勤";
            }
        }
    }
}

封装检测当天是否可以签到(Web层)

在 com.example.emos.wx.controller 包中,创建 CheckinController 类

@RequestMapping("/checkin")
@RestController
@Api("签到模块Web接口")
@Slf4j
public class CheckinController {
    @Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private CheckinService checkinService;

    @GetMapping("/validCanCheckIn")
    @ApiOperation("查看用户今天是否可以签到")
    public R validCanCheckIn(@RequestHeader("token") String token) {
        int userId = jwtUtil.getUserId(token);
        String result = checkinService.validCanCheckIn(userId, DateUtil.today());
        return R.ok(result);
    }
}

实现Shiro认证功能

一、认证与授权执行流程

之前我们在配置Shiro+JWT的时候,Shiro的认证与授权的实现功能并没有完成。 

 

        现在Controller中的 validCanCheckIn() 方法,并不是Shiro放行请求的Web方法。所以发送给validCanCheckIn() 方法的请求一定会被Shiro拦截下来,先由 OAuth2Filter 检查请求头的Token是否合法。如果没问题,接下来就要由 OAuth2Realm 中的 doGetAuthenticationInfo() 方法来颁发认证对象。请求被赋予了认证对象,那么请求才会被发送到Web方法来执行。

二、查询用户信息

        因为在认证方法里面要返回认证对象,认证对象创建的时候要传入用户信息和令牌,传入 Realm 类的名字,所以我们这里就要查询用户信息,然后判断用现在是在职还是离职状态。如果是在职状态,那就可以创建认证对象,反之就抛出异常。 

编辑 TbUserDao.xml 文件,添加查询方法 

<select id="searchById" parameterType="int" resultType="com.example.emos.wx.db.pojo.TbUser"> 
    SELECT
    id, open_id, nickname, photo, name, sex, tel, role, root, dept_id, status, create_time
    FROM tb_user WHERE id=#{userId} AND status = 1
</select>

编辑 TbUserDao.java 接口,添加抽象方法 

public TbUser searchById(int userId);

编辑 UserService.java 接口,添加抽象方法

public TbUser searchById(int userId);

编辑 UserServiceImpl.java 类,实现抽象方法 

@Override
public TbUser searchById(int userId) { 
    TbUser user = userDao.searchById(userId);
    return user; 
}

二、实现认证方法

编辑 OAuth2Realm.java 文件,修改 doGetAuthenticationInfo() 方法

/**
 * 认证(登录时调用) 
 */

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 
    String accessToken = (String) token.getPrincipal();
    int userId = jwtUtil.getUserId(accessToken);
    //查询用户信息
    TbUser user = userService.searchById(userId);
    if(user==null){
        throw new LockedAccountException("账号已被锁定,请联系管理员");
    }
    SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(user, accessToken, getName());
    return info;
}

实现Shiro 授权功能

        认证功能和JWT绑定在一起。只要OAuth2Filter过滤器认定客户端提交的令牌没有问题,就可以看作用户成功登录。Shiro颁发认证对象,HTTP请求才可以继续往下传递。授权和RBAC权限模型相关。

        认证对象封装了用户信息,所以授权方法中可以得到用户信息。

一、实现授权方法

        Shiro每次验证权限之前,都要执行授权方法,把用户具有的权限封装成权限对象,然后放行请求。接下来Web方法的 @RequiresPermissions 注解,会从权限对象中提取权限数据,跟要求的权限作比较。如果用户具有该Web方法要求的权限,那么Web方法就会正常执行。反之则返回异常消息。 

修改 OAuth2Realm.java 中的 doGetAuthorizationInfo() 授权方法。 

/**
 * 授权(验证权限时调用) 
 */

@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection collection) { 
    TbUser user = (TbUser) collection.getPrimaryPrincipal();
    int userId = user.getId();
    //用户权限列表
    Set<String> permsSet = userService.searchUserPermissions(userId);
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    info.setStringPermissions(permsSet);
    return info;
}

二、添加权限验证注解

        我们创建Web方法的时候,如果希望只有满足相关权限的用户才能调用这个Web方法,我们只需要给Web方法添加上 @RequiresPermissions 注解即可。

@PostMapping("/addUser") 
@ApiOperation("添加用户") 
@RequiresPermissions(value = {"ROOT", "USER:ADD"}, logical = Logical.OR) 
public R addUser() { 
    return R.ok("用户添加成功");
}

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

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

相关文章

HTTP调用:你考虑到超时、重试、并发了吗?

今天&#xff0c;我们一起聊聊进行 HTTP 调用需要注意的超时、重试、并发等问题。 与执行本地方法不同&#xff0c;进行 HTTP 调用本质上是通过 HTTP 协议进行一次网络请求。网络请求必然有超时的可能性&#xff0c;因此我们必须考虑到这三点&#xff1a; 首先&#xff0c;框架…

单例模式(Singleton)

定义 单例是一种创建型设计模式&#xff0c;让你能够保证一个类只有一个实例&#xff0c;并提供一个访问该实例的全局节点。 前言 1. 问题 单例模式同时解决了两个问题&#xff0c;所以违反了单一职责原则&#xff1a; 保证一个类只有一个实例。为该实例提供一个全局访问节…

react签字功能 react-signature-canvas

react签字功能 react-signature-canvas . 前几天一个月薪35k的兄弟&#xff0c;给我推了一个人工智能学习网站&#xff0c;看了一段时间挺有意思的。包括语音识别、机器翻译等从基础到实战都有&#xff0c;很详细&#xff0c;分享给大家。大家及时保存&#xff0c;说不定啥时…

【MOOC 作业】第4章 网络层

不是标答也不是参考答案 仅从个人理解出发去做题 1、(20分) 考虑如图示的网络。 a. 假定网络是一个数据报网络。显示路由器 A 中的转发表&#xff0c;其中所有指向主机 H3 的流量通过接口 3 转发。 目的网络链路接口H33 b. 假定网络是一个数据报网络。你能写出路由器 A 中的…

K8S系列文章之 部署MySQL数据库

1 编写 mysql.yaml文件 apiVersion: v1 kind: Namespace metadata:name: devops # Namespace 的名称 --- apiVersion: apps/v1 kind: Deployment metadata:name: devops-mysql # deployment控制器名称namespace: devops spec:replicas: 1revisionHistoryLimit: 5strategy:…

Maven及IDEA配置

1.Maven的安装及环境变量配置 1. 下载压缩包&#xff0c;解压到指定位置&#xff1b; 2. 在系统环境变量中配置 maven 的 bin 路径&#xff1b; 3. 配置一下 maven 的本地仓库位置和阿里云镜像&#xff08;推荐大家下载 notepad 进行修改配置&#xff09;&#xff1b; 在 …

Mysql高阶语句与MySQL存储过程

Mysql高阶语句 准备环境&#xff08;1&#xff09; 一、MySQL高阶进阶SQL语句1、select2、distinct3、where4、and or5、in6、between7、通配符8、order by9、函数数学函数字符串函数 10、group by11、having12、别名13、子查询13、EXISTS 二、MySQL高阶进阶SQL语句2环境准备&a…

DINDIEN

DIEN模型 DIN存在的问题&#xff1a; DIN引入了attention机制来通过用户历史行为数据对用户兴趣进行建模&#xff0c;而缺乏对具体行为背后的序列信息或者说依赖关系进行专门的建模&#xff0c;也就是没法捕捉到用户的兴趣变化过程。 DIEN的改动&#xff1a; 这个模型既然是…

为什么黑客不黑/攻击赌博网站?

攻击了&#xff0c;只是你不知道而已&#xff01; 同样&#xff0c;对方也不会通知你&#xff0c;告诉你他黑了赌博网站。 攻击赌博网站的不一定是正义的黑客&#xff0c;也可能是因赌博输钱而误入歧途的法外狂徒。之前看过一个警方破获的真实案件&#xff1a;28岁小伙因赌博…

Vue3 组合式 API

前言 传统的组件随着业务复杂度越来越高&#xff0c;代码量会不断的加大&#xff0c;整个代码逻辑都不易阅读和理解。Vue3 使用组合式 API 的地方为 setup。在 setup 中&#xff0c;我们可以按逻辑关注点对部分代码进行分组&#xff0c;然后提取逻辑片段并与其他组件共享代码。…

【FFmpeg实战】编解码 AVCodec

转载自&#xff1a;https://www.cnblogs.com/wangyaoguo/p/8192273.html FFmpeg编解码 FFmpeg支持绝大多数视频编解码格式&#xff0c;如何遍历FFmpeg编解码器&#xff1f; 编解码器以链表形式存储&#xff0c;使用av_codec_next() 函数可以获取编解码器指针&#xff0c;当参数…

【YOLO】yolov5训练自己的数据集

文章目录 0 前期教程1 前言2 准备数据集2.1 数据集来源2.2 数据集结构介绍2.3 标签格式的转换 3 训练以及训练结果3.1 训练3.2 测试 4 数据标注5 后续教程 0 前期教程 【Python】朴实无华的yolov5环境配置 1 前言 上面前期教程中&#xff0c;大致介绍了yolov5开发环境的配置方…

Windows 10 安装 Redis

安装 Redis 1&#xff1a;下载 下载 Windows 版本的 Redis&#xff0c;点击这里 下载redis 2&#xff1a;解压 解压下载的 zip 包到任意目录&#xff0c;如我的目录&#xff1a; 3&#xff1a;启动 命令行进入刚才解压文件的根目录下&#xff0c;然后执行如下命令即可&a…

跌倒检测 关节点角度数学计算

参考&#xff1a; https://github.com/GitGudwl/MediapipePoseEstimationForFallDetection/tree/main https://blog.csdn.net/weixin_45824067/article/details/130646962 1、mediapipe 根据关节点角度计算 1、11与12取中间点&#xff0c;记为center_up; 23 与24取中间点记为c…

为什么自学Python会从入门到放弃?

前言 Python现在非常火&#xff0c;语法简单而且功能强大&#xff0c;很多同学都想学Python&#xff01;所以蛋糕给各位看官们准备了高价值Python学习视频教程及相关电子版书籍&#xff0c;欢迎前来领取&#xff01; 下面小编与大家分享一下自学Python的人&#xff0c;放弃的…

【unity造轮子】Unity ShaderGraph使用教程与各种特效案例(持续更新)

文章目录 一、前言二、ShaderGraph1.什么是ShaderGraph2.在使用ShaderGraph时需要注意以下几点&#xff1a;3.优势4.项目 三、实例效果外发光进阶&#xff1a;带方向的菲涅尔边缘光效果裁剪进阶 带边缘色的裁剪溶解进阶 带边缘色溶解卡通阴影水波纹积雪效果不锈钢效果UV抖动水波…

使用编码工具

本文主要介绍了对句子编码的过程&#xff0c;以及如何使用PyTorch中自带的编码工具&#xff0c;包括基本编码encode()、增强编码encode_plus()和批量编码batch_encode_plus()。 一.对一个句子编码例子 假设想在要对句子’the quick brown fox jumps over a lazy dog’进行编码…

【K8S系列】深入解析K8S存储

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用来标记二级论点 Kubernetes (k8s) 是一…

ppp协议,一文带你了解

一、PPP协议简介 PPP&#xff08;Point-to-Point Protocol&#xff09;是一种数据链路层协议&#xff0c;用于在两个节点之间建立点对点的数据通信连接。PPP协议是TCP/IP协议族中的一员&#xff0c;它可以在串行通信线路上传输IP数据包&#xff0c;支持多种网络层协议&#xff…

C++ Primer 第11章关联容器

11.1 使用关联容器 map类型通常被常被称为关联数组。关联数组与正常数组类似&#xff0c;不同之处在于其下标不必是整数set就是关键字的简单集合&#xff0c;当想知道一个值是否存在时&#xff0c;set是最有用的 使用map #include<iostream> #include<string> #…