代码量:
- 移动端:30000+
- 后端:5000+
- 移动端:uni-app + Vue + JavaScript + Less + 微信小程序
- 后端:SpringBoot + SpringMVC + MyBatis + Shiro+ JWT + Quartz + ThreadPool + RabbitMQ + Docker
- 移动端源码
- 后端源码
后端:IDEA
前端:微信小程序开发工具 + HBuilderX
虚拟机:VirtualBox,Linux系统采用CentOS
第二章 后端环境搭建基础
- 利用Maven创建Spring Boot项目
- 配置MySQL、MongoDB、Redis数据源
- 整合SSM框架
- 自定义异常类和封装结果集
- 集成Swagger,便于调用测试Web方法
- 配置后端验证功能
- 抵御跨站脚本XSS攻击
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。
比如用户在发帖或注册时,文本框中输入
,如果不经过转义,保存到数据库里后,将来渲染时会执行该代码。
所以最有效的办法就是将用户输入的数据进行转义。
如果重写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); }@Override public String getParameter(String name) { String value = https://www.it610.com/article/super.getParameter(name); if(!StrUtil.hasEmpty(value)){ value = HtmlUtil.filter(value); } return value; }@Override public 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; }@Override public Map, String[]> getParameterMap() { Map, String[]> parameters = super.getParameterMap(); Map, 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 = https://www.it610.com/article/values[i]; if(!StrUtil.hasEmpty(value)){ value = HtmlUtil.filter(value); } values[i] = value; } map.put(key, values); } } return map; }@Override public String getHeader(String name) { String value = super.getHeader(name); if(!StrUtil.hasEmpty(value)){ value = HtmlUtil.filter(value); } return value; }@Override public 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, Object> map = JSONUtil.parseObj(body.toString()); Map, 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() { @Override public boolean isFinished() { return false; }@Override public boolean isReady() { return false; }@Override public void setReadListener(ReadListener readListener) {}@Override public 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 { @Override public void init(FilterConfig filterConfig) throws ServletException {}@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { XssHttpServletRequestWrapper wrapper = new XssHttpServletRequestWrapper((HttpServletRequest) servletRequest); filterChain.doFilter(wrapper, servletResponse); }@Override public void destroy() {} }
- 整合shiro和jwt
shiro是进行认证与授权的框架,jwt是用来生成、验证token的
- 刷新token
客户端和服务端存一样的token,服务端的有效时间是客户端的2倍,当客户端的token过期后,去服务端的redis中查找token是否过期,如果还未过期,则生成新的token;如果服务端的token也过期,那么就要让用户重新登录
- 点击注册时,微信申请临时授权,微信会发送一个临时授权字符串
- 将字符串传给后端,后端向微信平台发送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中返回。
【第二个项目---EMOS企业在线办公小程序】如果某个web方法需要用户具有相关权限,则加上@RequiresPermissions注解即可
- 认证:从token中获取userId,然后查询数据库中是否有该用户,如果有的话将user对象,token等添加到info里返回
- 了解人脸签到模型的全部流程
- 小程序端判定是否可以签到,如果不可以的话按钮为禁用状态;可以的话,拍照,点击签到,通过getLocation( )获取地理坐标,然后腾讯云位置服务转为真实地址,将地址和拍照图片的url传给后端Java程序
- Java拿到前端传来的信息,先判断是否存在该照片的人脸模型,如果不存在则选择创建或不创建,并发送给python程序进行创建;如果存在则发送给python程序该人脸模型是否属于该用户。识别成功后,判断签到地区疫情风险等级(发送给本地宝h5页面,并用JSOUP解析返回的响应),如果为高风险则发送警告邮件。最后保存签到记录
- 开通腾讯云位置服务,把坐标转为地址
- 在Docker中部署人脸识别程序
- 获取签到地点的疫情风险等级,发送邮件
- 判断当前时刻能否执行签到
- 执行人脸签到,记录签到结果
- 新员工创建人脸模型数据
- 编写签到成功页面静态内容
- 编写代码查询签到成功页面相关数据
- 编写用户页面,封装移动端权限验证函数
- 编写我的考勤页面静态内容
- 查询月考勤数据
- 分析消息模块的设计原理
- RabbitMQ的入门与安装
- 设计消息模块的MVC代码
- 编写线程任务类实现消息的收发
- 在其他业务流程中调用消息模块
- 设计静态页面
- 实现会议列表分页显示功能
- 动态编辑参会成员
- 成功部署工作流项目
- 实现会议的添加、修改和删除
- 创建在线审批页面和审批详情页面
- 完成在线审批功能
- 开通腾讯云TRTC服务
- 可以在线多人视频会议
- 实现首页的日历和会议列表
推荐阅读
- 到底为什么你的APP项目烂尾了()
- 掌上快递 APP 项目之概述篇
- AutoMapper实际项目运用
- 项目在App Store的展示信息
- Python|毕业设计-基于Python爬虫的疫情数据可视化系统
- 如何解决tomcat启动 ssm项目出现乱码
- 构建一个简单的Spring Boot项目
- 项目|基于springboot的疫情社区管理系统---V1【数据接口异常未修复】
- harmonyos|HarmonyOS应用开发【项目实践】——专栏介绍(作者(TDTX))