Spring boot + Vue2 整合人脸识别登录

我这里使用的是百度云的人脸库,没有的可以申请一下

百度智能云-登录

直接上代码实例

我是在若依集成的人脸识别登录

这里先添加人脸 具体参数可以去看一下

配置文件

复制代码
package com.shopgoods.auth.config;

import com.baidu.aip.face.AipFace;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
*@Author:FengZekun
*@Description:
*@name:Buida
*@Date:2024/11/24  19:40
*/
@Component
public class BaiduFaceApi {

    @Value("${baidu.face.appId}")
    public String APP_ID;
    @Value("${baidu.face.apiKey}")
    public String API_KEY;
    @Value("${baidu.face.secretKey}")
    public String SECRET_KEY;

    public AipFace getAipFace() {
        // 初始化一个AipFace
        return new AipFace(APP_ID, API_KEY, SECRET_KEY);
    }

}

@RequestMapping("/face")
@RestController
@CrossOrigin
public class FaceController {

    @Autowired
    private BaiduFaceApi baiduFaceApi;

    @Autowired
    private SysLoginService sysLoginService;


    /**
     * 人脸识别用户信息
     **/
    @PostMapping("/faceLogin")
    @ResponseBody
    public Result<SysUser> faceLogin(@RequestParam("file") MultipartFile file) {
        SysUser userInfo = sysLoginService.faceLogin(file);
        return Result.success(userInfo);
    }

    /**
     * 人脸信息注册
     **/
    @PostMapping("/registerFace")
    @ResponseBody
    public Result registered(@RequestParam("file") MultipartFile file,
                             @RequestParam("id") String id) {
        // 传入可选参数调用接口
        HashMap<String, String> options = new HashMap<>();
        options.put("user_info", "user's info");
        options.put("quality_control", "NORMAL");
        options.put("liveness_control", "NONE");
        options.put("action_type", "REPLACE");
        String image = sysLoginService.getImages(file);
        String imageType = "BASE64";
        String groupId = "demo";
        String userId = id;
        // 人脸注册
        JSONObject res = baiduFaceApi.getAipFace().addUser(image, imageType, groupId, userId, options);
        System.out.println(res);
        System.out.println(res.toString(2));
        return Result.success(res.get("result").toString());
    }

这是人脸登录接口

复制代码
import request from '@/utils/request'
/**
 * 人脸识别返回用户信息
 * @param formData
 * @returns {*}
 */
export function faceLogin(formData) {
  return request({
    url: '/auth/face/faceLogin',
    method: 'post',
    data: formData,
    headers: {			//设置上传请求头
      'Content-Type': 'multipart/form-data'
    },
  })
}

/**
 *
 *人脸注册
 */
export function registered(formData, id) {
  return request({
    url: '/auth/face/registerFace',
    method: 'post',
    data: formData,
    params: {
      id
    }
    ,
    headers: {			//设置上传请求头
      'Content-Type': 'multipart/form-data'
    },
  })
}

人脸登录前端vue代码

复制代码
<template>
  <div id="bbb">
    <router-view></router-view>
    <h1>人脸登录</h1>
    <video
      id="videoCamera"
      :width="videoWidth"
      :height="videoHeight"
      :x5-video-player-fullscreen="true"
      autoplay
    ></video>
    <canvas
      style="display: none"
      id="canvasCamera"
      :width="videoWidth"
      :height="videoHeight"
    ></canvas>
    <br>
    <el-button type="primary" plain @click="setImage()">手动拍照</el-button>
    <!-- <p class="fail_tips"></p>
    // 给外面盒子设置宽高,可以限制拍照图片的大小位置范围
    <div class="result_img">
      <img :src="imgSrc" alt class="tx_img" width="100%" height="100%" />
    </div>
    <p class="res_tips">效果展示</p> -->
  </div>
</template>
<script>

import Cookies from 'js-cookie'
import { faceLogin } from '../api/face/face'

export default {
  name: 'FaceIndex',
  data() {
    return {
      // 视频调用相关数据开始
      videoWidth: 500,
      videoHeight: 400,
      imgSrc: '',
      thisCancas: null,
      thisContext: null,
      thisVideo: null,
      openVideo: false,
      //视频调用相关数据结束
      postVideoImg: '',// 图片上传后获取的url链接,
      loginForm: {
        username: 'admin',
        password: 'admin123',
        rememberMe: false,
        code: '',
        uuid: '',
        typeId: 1
      }
    }
  },
  mounted() {
    // 第一步打开摄像头
    this.getCompetence() //调用摄像头
  },
  methods: {
    // 第三步、拍照图转换file格式上传,
    // 第四步、获取图片url链接
    async postImg() {
      let formData = new FormData()
      formData.append('file', this.base64ToFile(this.imgSrc, 'png'))
      formData.append('flag', 'videoImg') // 额外参数
      //使用axios对应的后台上传图片接口
      let result = await faceLogin(formData)
      console.log(result)
      if (result.code == 200) {
        this.loginForm.username = result.data.userName
        this.$store.dispatch('Login', this.loginForm).then(() => {
          this.$router.push({ path: this.redirect || '/' }).catch(() => {
          })
        })
      } else {
        this.$message({
          message: '登录失败,图像不合格',
          center: true,
          type: 'error',
          showClose: true
        })
      }
      return false
    },

    // 调用权限(打开摄像头功能)
    getCompetence() {
      var _this = this
      _this.thisCancas = document.getElementById('canvasCamera')
      _this.thisContext = this.thisCancas.getContext('2d')
      _this.thisVideo = document.getElementById('videoCamera')
      _this.thisVideo.style.display = 'block'
      // 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {}
      }
      // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
      // 使用getUserMedia,因为它会覆盖现有的属性。
      // 这里,如果缺少getUserMedia属性,就添加它。
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function(constraints) {
          // 首先获取现存的getUserMedia(如果存在)
          var getUserMedia =
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.getUserMedia
          // 有些浏览器不支持,会返回错误信息
          // 保持接口一致
          if (!getUserMedia) {
            //不存在则报错
            return Promise.reject(
              new Error('getUserMedia is not implemented in this browser')
            )
          }
          // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
          return new Promise(function(resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject)
          })
        }
      }
      var constraints = {
        audio: false,
        video: {
          width: this.videoWidth,
          height: this.videoHeight,
          transform: 'scaleX(-1)'
        }
      }
      navigator.mediaDevices
        .getUserMedia(constraints)
        .then(function(stream) {
          // 旧的浏览器可能没有srcObject
          if ('srcObject' in _this.thisVideo) {
            _this.thisVideo.srcObject = stream
          } else {
            // 避免在新的浏览器中使用它,因为它正在被弃用。
            _this.thisVideo.src = window.URL.createObjectURL(stream)
          }
          _this.thisVideo.onloadedmetadata = function(e) {
            _this.thisVideo.play()
          }
        })
        .catch((err) => {
          console.log(err)
        })
    },
    //  第二步、绘制图片(拍照功能)
    setImage() {
      var _this = this
      // canvas画图
      _this.thisContext.drawImage(_this.thisVideo, 0, 0)
      // 获取图片base64链接
      var image = this.thisCancas.toDataURL('image/png')
      _this.imgSrc = image //赋值并预览图片

      //这里是调用上传图片接口=====
      this.postImg() // 绘制完图片调用图片上传接口
    },
    // 关闭摄像头
    stopNavigator() {
      this.thisVideo.srcObject.getTracks()[0].stop()
    },

    // base64 转为 file
    base64ToFile(urlData, fileName) {
      let arr = urlData.split(',')
      let mime = arr[0].match(/:(.*?);/)[1]
      let bytes = atob(arr[1]) // 解码base64
      let n = bytes.length
      let ia = new Uint8Array(n)
      while (n--) {
        ia[n] = bytes.charCodeAt(n)
      }
      return new File([ia], fileName, { type: mime })
    }
  },
  destroyed: function() {
    // 离开当前页面
    this.stopNavigator() // 关闭摄像头
  }
}
</script>
<style>
.result_img {
  width: 226px;
  height: 195px;
  background: #d8d8d8;
}

#bbb {
  width: 500px;
  text-align: center;
  margin: auto;
}
</style>

注册人脸前端代码

复制代码
<template>
  <div id="aaa">
    <h1>人脸信息注册</h1>
    <video
      id="videoCamera"
      :width="videoWidth"
      :height="videoHeight"
      :x5-video-player-fullscreen="true"
      autoplay
    ></video>
    <canvas
      style="display: none"
      id="canvasCamera"
      :width="videoWidth"
      :height="videoHeight"
    ></canvas>
    <br>
    <el-button type="primary" plain @click="setImage()">手动拍照</el-button>
    <p class="fail_tips"></p>
    <!-- <div class="result_img">
      <img :src="imgSrc" alt class="tx_img" width="100%" height="100%" />
    </div>
    <p class="res_tips">效果展示</p> -->
  </div>
</template>
<script>



import { registered } from '../../../api/face/face'

export default {
  data() {
    return {
      id: localStorage.getItem("userId"),
      // 视频调用相关数据开始
      videoWidth: 500,
      videoHeight: 400,
      imgSrc: "",
      thisCancas: null,
      thisContext: null,
      thisVideo: null,
      openVideo: false,
      //视频调用相关数据结束
      postVideoImg: "", // 图片上传后获取的url链接
    };
  },
  mounted() {
    // 第一步打开摄像头
    this.getCompetence(); //调用摄像头
  },
  methods: {
    // 第三步、拍照图转换file格式上传,
    // 第四步、获取图片url链接
    async postImg() {
      let formData = new FormData();
      formData.append("file", this.base64ToFile(this.imgSrc, "png"));
      formData.append("flag", "videoImg"); // 额外参数
      //使用axios对应的后台上传图片接口
      await registered(formData, this.id).then(result=>{
        console.log(result.data);
        if (result.data.data != "null") {
          this.$message({
            message: "上传成功",
            type: "success",
            center: true,
            showClose: true,
          });
        } else {
          this.$message({
            message: "上传失败,图像不合格",
            center: true,
            type: "error",
            showClose: true,
          });
        }
      })
    },

    // 调用权限(打开摄像头功能)
    getCompetence() {
      var _this = this;
      _this.thisCancas = document.getElementById("canvasCamera");
      _this.thisContext = this.thisCancas.getContext("2d");
      _this.thisVideo = document.getElementById("videoCamera");
      _this.thisVideo.style.display = "block";
      // 获取媒体属性,旧版本浏览器可能不支持mediaDevices,我们首先设置一个空对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象
      // 使用getUserMedia,因为它会覆盖现有的属性。
      // 这里,如果缺少getUserMedia属性,就添加它。
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function (constraints) {
          // 首先获取现存的getUserMedia(如果存在)
          var getUserMedia =
            navigator.webkitGetUserMedia ||
            navigator.mozGetUserMedia ||
            navigator.getUserMedia;
          // 有些浏览器不支持,会返回错误信息
          // 保持接口一致
          if (!getUserMedia) {
            //不存在则报错
            return Promise.reject(
              new Error("getUserMedia is not implemented in this browser")
            );
          }
          // 否则,使用Promise将调用包装到旧的navigator.getUserMedia
          return new Promise(function (resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject);
          });
        };
      }
      var constraints = {
        audio: false,
        video: {
          width: this.videoWidth,
          height: this.videoHeight,
          transform: "scaleX(-1)",
        },
      };
      navigator.mediaDevices
        .getUserMedia(constraints)
        .then(function (stream) {
          // 旧的浏览器可能没有srcObject
          if ("srcObject" in _this.thisVideo) {
            _this.thisVideo.srcObject = stream;
          } else {
            // 避免在新的浏览器中使用它,因为它正在被弃用。
            _this.thisVideo.src = window.URL.createObjectURL(stream);
          }
          _this.thisVideo.onloadedmetadata = function (e) {
            _this.thisVideo.play();
          };
        })
        .catch((err) => {
          console.log(err);
        });
    },
    //  第二步、绘制图片(拍照功能)
    setImage() {
      var _this = this;
      // canvas画图
      _this.thisContext.drawImage(_this.thisVideo, 0, 0);
      // 获取图片base64链接
      var image = this.thisCancas.toDataURL("image/png");
      _this.imgSrc = image; //赋值并预览图片

      //这里是调用上传图片接口=====
      this.postImg(); // 绘制完图片调用图片上传接口
    },
    // 关闭摄像头
    stopNavigator() {
      this.thisVideo.srcObject.getTracks()[0].stop();
    },

    // base64 转为 file
    base64ToFile(urlData, fileName) {
      let arr = urlData.split(",");
      let mime = arr[0].match(/:(.*?);/)[1];
      let bytes = atob(arr[1]); // 解码base64
      let n = bytes.length;
      let ia = new Uint8Array(n);
      while (n--) {
        ia[n] = bytes.charCodeAt(n);
      }
      return new File([ia], fileName, {type: mime});
    },
  },
  destroyed: function () {
    // 离开当前页面
    this.stopNavigator(); // 关闭摄像头
  },
};
</script>
<style>
.result_img {
  width: 226px;
  height: 195px;
  background: #d8d8d8;
  position: absolute;
  top: 100px;
  right: -100px;
}

#aaa {
  width: 500px;
  text-align: center;
  margin: auto;
  position: relative;
}
</style>

这里是一个页面效果就不展示小编帅气的俊脸了

相关推荐
2501_933923253 分钟前
Spring Bean作用域揭秘:单例、原型、请求与会话的区别
java·后端·spring·java-ee
学编程就要猛20 分钟前
基于Spring AI 的智能聊天机器人
java·spring ai·chat robot
修炼室23 分钟前
Java开发工程师笔试经验贴【高频知识】
java
木井巳35 分钟前
【记忆化搜索】最长递增子序列
java·算法·leetcode·深度优先·剪枝·推荐算法
杨杨杨大侠42 分钟前
知识库已经有了,Java 程序员还要做什么?Spring AI RAG 实战
java·openai·ai编程
伊信1 小时前
Spring AI 基础学习与应用
java·后端
夜郎king1 小时前
基于 Java + Playwright 实现网站自动访问与数据采集(以腾讯云开发者社区为例)
java·playwright·网页数据获取
Anastasiozzzz1 小时前
重新定义 Agent 基建:Redis 在现代 AI 与智能体系统中的工程实践
java·人工智能·redis·ai
careathers1 小时前
【数据结构】队列
java·数据结构
步行cgn1 小时前
Spring 通过 factory-method 实例化 Bean 详解与常见错误排查
java·后端