第二个项目---EMOS企业在线办公小程序
代码量:
- 移动端:30000+
- 后端:5000+
技术栈:
- 移动端:uni-app + Vue + JavaScript + Less + 微信小程序
- 后端:SpringBoot + SpringMVC + MyBatis + Shiro+ JWT + Quartz + ThreadPool + RabbitMQ + Docker
源码地址:
- 移动端源码
- 后端源码
第一章 安装软件
数据库:MySQL + MongoDB + Redis
后端:IDEA
前端:微信小程序开发工具 + HBuilderX
虚拟机:VirtualBox,Linux系统采用CentOS
第二章 后端环境搭建基础
利用Maven创建Spring Boot项目
配置MySQL、MongoDB、Redis数据源
整合SSM框架
自定义异常类和封装结果集
集成Swagger,便于调用测试Web方法
配置后端验证功能
抵御跨站脚本XSS攻击
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
比如用户在发帖或注册时,文本框中输入
<script>alert(123)</script>
,如果不经过转义,保存到数据库里后,将来渲染时会执行该代码。所以最有效的办法就是将用户输入的数据进行转义。
如果重写
HttpServletRequest
类,需要覆盖的方法太多,非常耗时。只需继承
HttpServletRequestWrapper
类,该方法为请求传入包装类,采用装饰器模式,可以随意修改其中的方法。package com.example.emos.wx.config.xss;import cn.hutool.core.util.StrUtil; import cn.hutool.http.HtmlUtil; import cn.hutool.json.JSONUtil;import javax.servlet.ReadListener; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.*; import java.nio.charset.Charset; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map;/*** @author 袁梦达 2019012364*/ public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {public XssHttpServletRequestWrapper(HttpServletRequest request) {super(request);}@Overridepublic String getParameter(String name) {String value = super.getParameter(name);if(!StrUtil.hasEmpty(value)){value = HtmlUtil.filter(value);}return value;}@Overridepublic String[] getParameterValues(String name) {String[] values = super.getParameterValues(name);if(values != null){for(int i = 0; i < values.length; i++){String value = values[i];if(!StrUtil.hasEmpty(value)){value = HtmlUtil.filter(value);}values[i] = value;}}return values;}@Overridepublic Map<String, String[]> getParameterMap() {Map<String, String[]> parameters = super.getParameterMap();Map<String, String[]> map = new LinkedHashMap<>();if(parameters != null){for (String key : parameters.keySet()) {String[] values = getParameterValues(key);for(int i = 0; i < values.length; i++){String value = values[i];if(!StrUtil.hasEmpty(value)){value = HtmlUtil.filter(value);}values[i] = value;}map.put(key, values);}}return map;}@Overridepublic String getHeader(String name) {String value = super.getHeader(name);if(!StrUtil.hasEmpty(value)){value = HtmlUtil.filter(value);}return value;}@Overridepublic ServletInputStream getInputStream() throws IOException {InputStream in = super.getInputStream();StringBuffer body = new StringBuffer();InputStreamReader reader = new InputStreamReader(in, Charset.forName("UTF-8"));BufferedReader buffer = new BufferedReader(reader);String line = buffer.readLine();while (line != null){body.append(line);line = buffer.readLine();}buffer.close();reader.close();in.close();Map<String, Object> map = JSONUtil.parseObj(body.toString());Map<String, Object> resultMap = new LinkedHashMap<>();for (String key : map.keySet()) {Object val = map.get(key);if(map.get(key) instanceof String){resultMap.put(key, HtmlUtil.filter(val.toString()));}else {resultMap.put(key, val);}}String str = JSONUtil.toJsonStr(resultMap);ByteArrayInputStream bain = new ByteArrayInputStream(str.getBytes());return new ServletInputStream() {@Overridepublic boolean isFinished() {return false;}@Overridepublic boolean isReady() {return false;}@Overridepublic void setReadListener(ReadListener readListener) {}@Overridepublic int read() throws IOException {return bain.read();}};} }
只定义该类还不够,必须写一个过滤器,让用户的请求是经过这个wrapper类,而不是正常的request方法
package com.example.emos.wx.config.xss;import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import java.io.IOException;/*** @author 袁梦达 2019012364*/@WebFilter(urlPatterns = "/*") public class XssFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {XssHttpServletRequestWrapper wrapper = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest);filterChain.doFilter(wrapper, servletResponse);}@Overridepublic void destroy() {} }
第三章 后端环境搭建进阶
整合shiro和jwt
shiro是进行认证与授权的框架,jwt是用来生成、验证token的
刷新token
客户端和服务端存一样的token,服务端的有效时间是客户端的2倍,当客户端的token过期后,去服务端的redis中查找token是否过期,如果还未过期,则生成新的token;如果服务端的token也过期,那么就要让用户重新登录
第四章 利用UNI-APP创建移动端
如何将员工账户和微信账号绑定
- 点击注册时,微信申请临时授权,微信会发送一个临时授权字符串
- 将字符串传给后端,后端向微信平台发送AppId、密钥、字符串换取OpenId
- 将OpenId、员工账户、头像、昵称等添加到数据库中
- 以后员工登录时,将登录时微信发出的OpenId与数据库中的OpenId去比对
第五章 登陆与注册
- 实现注册超级管理员
- RBAC权限模型
- 封装小程序的全局路径和Ajax请求
- 实现超级管理员登陆
第六章 人脸签到基础
开通对象云存储服务
实现首页部分功能
- 轮播图采用标签,里面嵌套
- 栏目导航采用flex布局
设计人脸签到页面
业务流程:拍照–>保存图片–>隐藏摄像区–>显示图片–>点击签到
一开始照片是隐藏的,当点击拍照后,照片显示出来,摄像区隐藏,然后拍照按钮变为签到按钮
微信小程序提供标签来调用系统相机,调用相机对象的takePhoto()方法即可拍照
缓存系统常量数据
sys_config数据表中保存了一些常量配置信息,如:考勤几点开始,几点结束等。需要在springboot启动时加载,缓存成java对象,全局都可以使用
流程:读取表得到一个list集合,封装了常量的名字和对应的值,然后遍历这个集合,对集合中每一个对象(有键值对),获取键和值,然后通过反射将常量类对应的变量(即键)加载,然后赋值
查询当前时刻是否可以签到
流程:
- dao层:
- 查询工作日表今天是否为工作日
- 查询节假日表今天是否为节假日
- 查询当前用户在今天是否签到过
- service层:
- 调用dao层的方法判断今天是否为工作日,不是的话直接返回无需签到
- 调用常量类中的签到开始和结束时间,判断现在是否可以签到
- 如果可以签到的话,调用dao层的第三个方法判断该用户是否签到过,如果没签到可以进行签到
- controller层:从token中获取userId,然后调用service
- dao层:
实现shiro认证与授权
认证:从token中获取userId,然后查询数据库中是否有该用户,如果有的话将user对象,token等添加到info里返回
授权:从认证后的对象中获取user对象,然后获取userId,根据userId在数据库中查找拥有的权限集合,添加到Info中返回。
如果某个web方法需要用户具有相关权限,则加上@RequiresPermissions注解即可
第七章 人脸签到进阶
- 了解人脸签到模型的全部流程
- 小程序端判定是否可以签到,如果不可以的话按钮为禁用状态;可以的话,拍照,点击签到,通过getLocation( )获取地理坐标,然后腾讯云位置服务转为真实地址,将地址和拍照图片的url传给后端Java程序
- Java拿到前端传来的信息,先判断是否存在该照片的人脸模型,如果不存在则选择创建或不创建,并发送给python程序进行创建;如果存在则发送给python程序该人脸模型是否属于该用户。识别成功后,判断签到地区疫情风险等级(发送给本地宝h5页面,并用JSOUP解析返回的响应),如果为高风险则发送警告邮件。最后保存签到记录
- 开通腾讯云位置服务,把坐标转为地址
- 在Docker中部署人脸识别程序
- 获取签到地点的疫情风险等级,发送邮件
- 判断当前时刻能否执行签到
- 执行人脸签到,记录签到结果
- 新员工创建人脸模型数据
第八章 人脸签到升级
- 编写签到成功页面静态内容
- 编写代码查询签到成功页面相关数据
- 编写用户页面,封装移动端权限验证函数
- 编写我的考勤页面静态内容
- 查询月考勤数据
第九章 系统通知模块
- 分析消息模块的设计原理
- RabbitMQ的入门与安装
- 设计消息模块的MVC代码
- 编写线程任务类实现消息的收发
- 在其他业务流程中调用消息模块
第十章 会议管理功能
- 设计静态页面
- 实现会议列表分页显示功能
- 动态编辑参会成员
- 成功部署工作流项目
- 实现会议的添加、修改和删除
第十一章 在线视频会议
- 创建在线审批页面和审批详情页面
- 完成在线审批功能
- 开通腾讯云TRTC服务
- 可以在线多人视频会议
- 实现首页的日历和会议列表
第二个项目---EMOS企业在线办公小程序相关推荐
- 如何利用开源项目,帮助企业免费搭建小程序官网
微信小程序是目前特别火的一款程序,也是一种全新的连接用户与服务的方式,它可以在微信内被便捷地获取和传播,同时具有出色的使用体验. 企业想自己搭建简单的小程序官网,可以使用开源的一些资源进行搭建,用到的 ...
- 腾讯在线教育小程序开发实践之路
前言: 小程序是一种新的开放能力, 开发者可以快速地开发一个小程序,便可以在微信内被便捷得获取和传播,同时具有出色的使用体验.随着近两年来小程序风口的爆发,越来越多的开发者.企业开始接入小程序,那么在 ...
- asp.net程序涉及案例_定制小程序 | 企业在开发小程序前需要满足哪些条件?
目前深圳小程序开发行业发展愈发迅速,小程序开发已成为目前的潮流趋势,制作属于自己的小程序刻不容缓.那么在开发小程序前,企业需要满足什么条件呢? 1.注册账号 万纵联小编告诉你,要想开发小程序,申请账号 ...
- 手撸一个在线学习在线教育小程序
最近有小伙伴找小孟开发了一个在线教育的小程序项目. 一,小程序介绍 微信小程序,它的简称是小程序,其英文名称叫做Mini Program,是一种不需要在手机应用商店里面下载就可以在微信平台当中立即使用 ...
- 券商如何借助企业微信、小程序、视频号提高营收转化?
近年来,小程序.视频号.企业微信联合打造了一个新的商业通信圈,越来越多的品牌及券商企业都入驻其中. 如今,具有直连12+亿微信客户优势的企业微信.商品交易总额近3万亿的小程序和日活跃用户数量超5亿的视 ...
- springboot md5加密_实在!基于Springboot和WebScoket,写了一个在线聊天小程序
基于Springboot和WebScoket写的一个在线聊天小程序 (好几天没有写东西了,也没有去练手了,就看了看这个...) 项目说明 此项目为一个聊天的小demo,采用springboot+web ...
- 食品加工企业自营商城小程序开发,帮助企业增加销售渠道,提高销量
随着生活水平的不断提高,人们对于食品质量提出了更高的要求.传统人们购买食品时只能到超市或者市场进行食品采购,需要花费一定的时间和精力,而且经过多层中间商赚取差价的原因性价比也并不高.在移动电商的时代发 ...
- 企业如何利用小程序引流?小程序常见的4个引流方法
迄今为止,相信很多企业都已经开发了小程序,那么下一步企业要面对的就是,如何推广引流小程序.只有这样才能为小程序获得更多的忠实用户,使小程序具有更大的价值.下面就为大家介绍一下,小程序最常用的推广引流方 ...
- 计算机毕业设计Python+uniapp基于微信小程序某企业考勤系统(小程序+源码+LW)
计算机毕业设计Python+uniapp基于微信小程序某企业考勤系统(小程序+源码+LW) 该项目含有源码.文档.程序.数据库.配套开发软件.软件安装教程 项目运行 环境配置: Pychram社区版+ ...
- 企业官网小程序有什么作用
现在基本上所有的企业都有自己的官网,不管企业的规模是大是小,建设一个官网是非常必要的.因为官网相当于企业的官方形象,它代表一种权威.官网一般是由企业建立并建设的网站,是企业的意志体现,有着自己的特独功 ...
最新文章
- 【C++】C++命名空间重定向
- 基于Spring可扩展Schema提供自定义配置支持
- Delphi2010组件/控件安装方法
- matplotlib,numpy自己动手安装
- 记录 之 tensorflow中几个常用的函数:tf.unstack,tf.concat() 和 tf.stack() 等
- android 05 桢布局:FrameLayout 网格布据 GridLayout
- toj 4604 搞笑版费马大定理
- java基础—Map集合的常见方法操作(java集合八)
- 叫你怎么恢复回收站已清空文件(转)
- python入门教程pdf-python基础教程:《Python编程无师自通》PDF版百度云下载
- 每一个与众不同的水瓶座
- 007---多态与多态性
- Codeforces Round #435 (Div. 2) E. Mahmoud and Ehab and the function[二分]
- redis重做从库时报Connection with master lost错误
- 英文顺序:第一~第N
- git创建本地版本仓库
- 制作字幕(一般方法)
- matlab的方法定义变量,Matlab定义变量怎么操作?定义变量方法介绍
- USBPD充电协议,快充协议IC,PD3.0芯片
- RCF—用于C++的进程间通讯(4)
热门文章
- 图像变换中的常用插值方法(含公式推导)
- 谷歌地图的级别与对应比例尺及分辨率探究
- wifi mesh测试软件,「可能是」最适合我的Mesh+WiFi6方案:Linksys Velop MX10600体验分享...
- 北大慕课(郭炜):程序设计与算法(一)编程题答案(全)
- centos8解压war包
- 【树莓派】在Raspbian下将wifi中继为有线网络
- 如何区分网线是几类的_怎么看网线是几类?
- 【算法竞赛学习笔记】弦图和区间图
- C语言——坦克大战(纯控制台显示)
- 019 [工具软件]窗体置顶 DeskPins