springboot校园交友网站1.0(Springboot+Mybatis+thymeleaf+人脸识别+语音助手+百度地图)

涉及技术

  • 前端:以HTML+CSS+JS为基础,以LayUI为前端框架
  • 后端:JAVA为语言基础,Springboot为后端框架,整合Mybatis替代了传统的JDBC模式,数据库是用的Mysql,模板引擎使用了Springboot推荐的Thymeleaf

数据库设计

项目的数据库设计改动过几次,以下是最终版本
在这里插入图片描述
表与表的关联性还是很强的,这里提一点,就是当一开始的测试数据不完整或者添加了太多不必要的数据时,可能涉及数据库的数据全部删除的再重添加,你可以选择使用触发器,或者使用以下的方式:
如果你是使用的SQLyog,那么你可以打开SQLyog点击上方的数据库,然后点击备份与导出,然后点击“以SQL转储文件备份数据库”,然后你可以在弹出框中选择“仅结构”,即可导出数据库的SQL脚本,再删除数据库,再运行脚本创建数据库(个人学习记录,哈哈)
在这里插入图片描述

前端搭建

前端的搭建我主要采用的是LayUI框架(好用!),这里就不多说,大家可以去官网学习学习,里面的各类组件都是直接可以使用的,官网链接如下:
LayUI框架
除此之外,注意些常见问题
在这里插入图片描述
注意在你的js最外面加上如下代码
在这里插入图片描述
其他相关问题 --> LayUI社区

后端实现

项目使用的是MVC设计模式(这里盗图了,具体在哪里看到的,忘记了,对不住了,兄弟),用户通过点击,发送请求,再通过控制层实现对持久层的调用,再交还数据给控制层,通过Thymeleaf模板嵌套至前端中,进行实时渲染,同时用户得到响应
在这里插入图片描述
通过maven创建JavaWeb项目,解决导入依赖的jar造成的不必要的冲突,在框架上,我们使用了SpringBoot,简化了繁琐的配置,我们整合了MyBatis,通过xml配置对数据库的数据进行映射,从而实现对数据库的操控,使用Druid数据源,可以有效监控并合理分配对数据库的连接

项目重点实现

搜索栏(模糊查询)

模糊查询

首页发布请求遍历

首页遍历

分类跳转

分类跳转
虽然都是概要图,但是我在最后配了项目百度云,你可以对比代码阅读,理解更加深刻

项目难点

图片是使用base64的格式存入数据库中(每个任务可以配多张图片)
like this:
任务配图
每个任务除了可以配图以外,还有其他很多属性,比如任务时间,任务地点等(都可以在上面的数据库设计中看到,对应task表),当我们想将任务配图像其他属性一样(比如任务时间,任务地点等)在前端通过thymeleaf中的th:each遍历出来时,才发现,任务配图和任务不是一张表(也就是 "pictures"表和 "task"表是分开的,只是通过task_id这个外键关联),所以在控制层中写了一个模型工具类(ModelUtil)

package com.kuang.utils;

import lombok.Data;

import java.util.List;

/**
 * @author HP
 */
@Data
public class ModelUtil<T> {
    /**模型对象*/
    private T obj;
    /**模型对象中图片base64数据集合 指上传多张图片*/
    private List<String> base64;
}

然后在控制层中的代码如下:

   /**
     * @return 首页
     */
    @RequestMapping(value = "/index", method = RequestMethod.GET, produces = "application/json;charset=utf-8")
    public String toMainPage(Model model){
        //导航栏  大小分类
        int parent_sort_id = 0;
        Collection<Sorts> sorts = indexService.getAll(parent_sort_id);
        model.addAttribute("sorts",sorts);
        Collection<Sorts> smallsorts = indexService.getAllSmallSorts(parent_sort_id);
        model.addAttribute("smallsorts",smallsorts);

        //发布的任务
        List<ModelUtil> m = new ArrayList<>();
        List<Task> tasks = indexService.getTaskAll();
        tasks.forEach(t -> {
            ModelUtil<Task> modelUtil = new ModelUtil<>();

            List<TaskPictures> taskPictures = indexService.getAllTaskPictures(t.getTaskId());
            List<String> bases = new ArrayList<>();
            taskPictures.forEach(p -> bases.add(new String(p.getTaskPicture(), StandardCharsets.UTF_8)));
            modelUtil.setObj(t);
            modelUtil.setBase64(bases);
            m.add(modelUtil);
        });
        model.addAttribute("tasks", m);

        return "fore/index";
    }

其次是在前端中的thymeleaf:
遍历首页任务
遍历效果如图:
首页遍历

接口调用(人脸识别+语音识别+百度地图API)

人脸识别

这一方面我在博客里多次提到过了,具体实现大家可以去看看我的java学生管理系统(百度人脸识别 + Swing + mysql + 邮件发送 )
里面涉及到了百度AI从注册到对单个参数的提取,可以帮助你实现人脸识别,在这次项目中唯一不同的是,我是通过H5打开的摄像头,而链接中因为用的是Swing,所以我当时采用的是opencv打开摄像头来实时监测人脸(它自带算法可以监测到人脸),下面附上H5打开摄像头的代码和一张比较重要的关系图

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>人脸识别</title>
</head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<style>

    #video {
        position: absolute;
        right: 0;
        top: 0;
        margin: -100px -240px auto;
    }

    #img {
        position: absolute;
        left: 0;
        top: 0;
    }

    .auto {
        position: absolute;
        left: 50%;
        top: 50%;
        height: 320px;
        margin-top: -160px;
    }

    button {
        cursor: pointer;
        margin: 0 auto;
        border: 1px solid #f0f0f0;
        background: #5CACEE;
        color: #FFF;
        width: 100px;
        height: 36px;
        line-height: 36px;
        border-radius: 8px;
        text-align: center;
        /*禁止选择*/
        -webkit-touch-callout: none;
        /* iOS Safari */
        -webkit-user-select: none;
        /* Chrome/Safari/Opera */
        -khtml-user-select: none;
        /* Konqueror */
        -moz-user-select: none;
        /* Firefox */
        -ms-user-select: none;
        /* Internet Explorer/Edge */
        user-select: none;
        /* Non-prefixed version, currently not supported by any browser */
    }
</style>

<body background="/static/img/face_bg.png">
    <div class="auto">
        <video id="video" width="480" height="320" autoplay></video>
        <canvas id="canvas" width="480" height="320" style="display: none;"></canvas>
        <div>
            <button id="capture" onclick="alert('请将正脸置于摄像头前');" style="display: none;"></button>
        </div>

    </div>


    <script>
        var file, stream;
        //访问用户媒体设备的兼容方法
        function getUserMedia(constraints, success, error) {
            if (navigator.mediaDevices.getUserMedia) {
                //最新的标准API
                navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
            } else if (navigator.webkitGetUserMedia) {
                //webkit核心浏览器
                navigator.webkitGetUserMedia(constraints, success, error)
            } else if (navigator.mozGetUserMedia) {
                //firfox浏览器
                navigator.mozGetUserMedia(constraints, success, error);
            } else if (navigator.getUserMedia) {
                //旧版API
                navigator.getUserMedia(constraints, success, error);
            }
        }

        let video = document.getElementById('video');
        let canvas = document.getElementById('canvas');
        let context = canvas.getContext('2d');

        function success(stream) {
            //兼容webkit核心浏览器
            let CompatibleURL = window.URL || window.webkitURL;
            //将视频流设置为video元素的源
            console.log(stream);
            stream = stream;
            //video.src = CompatibleURL.createObjectURL(stream);
            video.srcObject = stream;
            video.play();
        }

        function error(error) {
            console.log(`访问用户媒体设备失败${error.name}, ${error.message}`);
        }

        if (navigator.mediaDevices.getUserMedia || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia) {
            //调用用户媒体设备, 访问摄像头
            getUserMedia({ video: { width: 480, height: 320 } }, success, error);
        } else {
            alert('不支持访问用户媒体');
        }

        // 获取base64图片链接
        document.getElementById('capture').addEventListener('click', function () {
            context.drawImage(video, 0, 0, 480, 320);
            // 获取图片base64链接
            var image_js = canvas.toDataURL('image/png');
            console.log(image_js);

            //ajax传输图片至后端
            $.ajax({
                async: false,
                type: "post",
                url: "/login/receiveData",
                data: { 'base64': JSON.stringify(image_js) },
                dataType: "json",
                mimeType: "multipart/form-data",
                success: function (data) {
                    alert(data.msg);
                    location.reload();

                    if (data.success) {
                        location.href = "/index";
                        $(".msg").stop(true, true).animate({
                            opacity: 1
                        }, 550, function () {
                            $(".msg").animate({
                                opacity: 0
                            }, 1500, function () {
                                location.href = "/index";
                            });
                        });
                    } else {
                        location.href = "/user/toLogin";
                    }
                },

                error: function (data) {
                }
            })


        });

        // 两秒后模拟点击
        setTimeout(function () {
            // IE
            if (document.all) {
                document.getElementById("capture").click();
            }
            // 其它浏览器
            else {
                var e = document.createEvent("MouseEvents");
                e.initEvent("click", true, true);
                document.getElementById("capture").dispatchEvent(e);
            }
        }, 2000);



    </script>
</body>

</html>

人脸识别总览图
展示效果:这是人脸注册的,和人脸登录页面基本一样(注册成功后跳转登录页,人脸登录后跳首页)
人脸识别展示图

语音识别

其实语音播报这块,我之前也发过博客,主要是利用语音播报(文字转语音)和实时录音并上传百度AI(语音转文字),就这两项即可实现简单的人机对话,大家可以移步至:
java+百度语音识别(语音助手)
而这次项目只是在首页加了一个小按钮,供用户点击,再将点击事件通过ajax传到后端的控制层,控制层再和持久层交互,这样实现语音操作数据库,当然你也可以加个工具类,通过语音播报的形式,实现人机对话(此时就有小伙伴要问了,你这不智能啊!还要手点,辣鸡!这个嘛,后面还在学习语音唤醒,敬请期待)
语音助手
以下是上图页面中关于语音助手的js(“Tiko”是上图黄色机器人按钮button的id,回调函数中主要是写的跳转到的对应分类页面,也就是我上面说的调用持久层的给予用户的响应)
语音助手js
总览关系图:(上传百度AI平台这块和人脸识别步骤基本一致,你可以多看看人脸识别是如何实现的)
语音识别总览图
控制层的代码涉及语音的比较广,我后面直接给项目代码,就不单独写出来了

百度地图API

这块调用我也只是小有涉及,不多但确实对我的项目有帮助,提升了用户体验
百度地图API
这块确实不难,我就不细说了,具体参看它的官网 --> 百度地图开放平台官网示例
这些示例都很好用,基本拿来即用,只是有一点很不好就是在定位方面,百度地图没法让我们准确定位到自己的位置,只能定位到城市级别的水平,我参看了其他几个地图开发平台好像都是这样

项目后续跟进(尽全力跟进,但不一定成,哈哈)

  1. 会加入语音唤醒,这样就不用点击按钮
  2. 加入消息通知(应该是通过消息队列)
  3. 设置会员等级,加入支付功能(支付即可成为会员,你懂的)
  4. 美化UI

项目百度云链接

分享给小伙伴们,希望能帮到你,共同努力!一起进步!(安装方式和相关配置都在链接中)
链接:https://pan.baidu.com/s/1sCaZIzTnGDJwgCrZeVog3Q
提取码:wbpe

  • 1
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
百度map,百度map API,百度地图 实现百度地图动态搜索、静态地图动态插入 mygw@163.com js 内容如下: /** 加载地图的主控类 */ var MapControl={ staticWith : 512,//链接静态图宽度 staticHeight : 320,//链接静态图的高度 container : 'mapcontainer',//显示map的节点id defzoom:12,//默认缩放比例 map : '', marker : '', city : '深圳', infoWinContent : '请移动此标记到您的婚礼地点位置!', /** 提示信息窗内容 */ infoOpts : { width : 100, // 信息窗口宽度 height: 50, // 信息窗口高度 title : "提示:" // 信息窗口标题 }, /** *默认显示窗口 */ defWindow : function(){ this.map = new BMap.Map(this.container); this.map.centerAndZoom(this.city,this.defzoom); // 通过城市名初始化地图 this.map.addEventListener("load", function(){ // 初始化方法执行完成后即可获取地图中心点信息 MapControl.marker = new BMap.Marker( this.getCenter()); // 创建标注 this.addOverlay(MapControl.marker ); // 将标注添加到地图中 MapControl.marker.enableDragging(); var infoWindow = new BMap.InfoWindow(MapControl.infoWinContent, MapControl.infoOpts); // 创建信息窗口对象 MapControl.marker.addEventListener("mouseover", function(){ this.openInfoWindow(infoWindow); // 打开信息窗口 }) MapControl.marker.addEventListener("mouseout", function(){ this.closeInfoWindow(); // 打开信息窗口 }) }) //map 增加操作 this.map.addControl(new BMap.NavigationControl()); this.map.addControl(new BMap.ScaleControl()); this.map.addControl(new BMap.OverviewMapControl()); this.map.addControl(new BMap.MapTypeControl()); }, /** * 搜索地址 */ search : function(address){ if(this.map=='' || this.map == 'undefined' || address=='' ){ return ; } this.city=address; this.defWindow(); }, /** * 获取静态图片地址 */ getStaticMap : function(){ if(this.map=='' || this.map == 'undefined' || this.marker=='' ){ return ; } var center=this.map.getCenter().lng+','+this.map.getCenter().lat; var markers= this.marker.getPosition().lng+','+this.marker.get

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值