学号 :20184131031 姓名 :李飞龙 班级 :18机器人4班
学号 :201841302153 姓名 :杨海林 班级 :18智能制造4班
指导老师:黎志雄
分工:杨海林:后端代码编写,前后端数据交互
李飞龙:前端,docker部署 ,实验报告编写
在全国人民共同抗击新型冠状病毒疫情的严峻形势下,为了让高校师生健康信息上报,方便地了解高校师生身体健康情况,做好高校内部的疫情防控工作与管理,很多高校都自建了健康上报系统
本实验项目作为课程的期末大作业,要求学生组队自主设计与实现一个健康上报系统,并可以Saas(软件即服务)架构实现云原生系统。
本实验项目要求学生团队设计实现的高校健康上报系统可以解决如下需求:
1、前端界面功能模块
a) 要求界面美观、简约,主题统一;
b) 调研国内相关系统界面的输入信息,设计前端各信息录入项目;
c) 有防止用户重复提交的功能;
d) 有加速渲染前端界面的设计。
2、后台管理端功能模块
a) 可以使用vue或其他前端框架构建,实现管理后台各个功能界面;
b) 要求界面简洁精美,主题统一;
c) 后台登陆逻辑需要接入腾讯防水墙,https://007.qq.com/ ;
d) 管理员账号管理模块;
e) 账号管理模块;
f) 有解决系统高并发问题的设计;
g) 提供大数据报表并导出Excel表格,相关管理人员通过报表可一目了然地查看相关信息;
h) 所有列表可以进行综合查询;
i) 所有列表可以导出excel文件或pdf文件。
1、项目架构
2、普通用户登录、注册
@RequestMapping("/login")
public String login(@ModelAttribute person per, Model model){
person person2 = perService.selectPerson(per.getPersonId());
String personId = per.getPersonId();
String password = per.getPassword();
if(person2 != null){
if(per.getPassword().equals(person2.getPassword())){
return "redirect:"+ personId + "/inputInfo";
}
else {
String str= "密码错误,请重新输入!";
model.addAttribute("personId", personId);
model.addAttribute("password", password);
model.addAttribute("passwordError", str);
return "index";
}
}
else {
String str= "该账号尚未注册,请先注册";
model.addAttribute("personId", personId);
model.addAttribute("password", password);
model.addAttribute("passwordError", str);
model.addAttribute("userError", str);
return "index";
}
}
@RequestMapping("/register")
public String register(){
return "register";
}
@RequestMapping("/insertPerson")
public String insertPerson(@ModelAttribute person per, Model model){
int flag = perService.insertPerson(per);
if (flag == 1){
String name = per.getName();
model.addAttribute("name", name);
return "registerSuccess";
}
else {
String name = per.getName();
String personId = per.getPersonId();
String password = per.getPassword();
model.addAttribute("name", name);
model.addAttribute("personId", personId);
model.addAttribute("password", password);
model.addAttribute("userExists","该用户已存在");
return "register";
}
}
前端显示效果:
3、管理员登录模块
@RequestMapping("/login")
public String login(@ModelAttribute person per, Model model){
person person2 = perService.selectPerson(per.getPersonId());
String personId = per.getPersonId();
String password = per.getPassword();
if(person2 != null){
if(per.getPassword().equals(person2.getPassword())){
if(person2.getFlag()==1)
return "redirect:/admin/personList";
else {
model.addAttribute("NotAdmin", "您不是管理员");
return "AdminLogin";
}
}
else {
String str= "密码错误,请重新输入!";
model.addAttribute("personId", personId);
model.addAttribute("password", password);
model.addAttribute("passwordError", str);
return "AdminLogin";
}
}
else {
String str= "该账号尚未注册,请先注册";
model.addAttribute("personId", personId);
model.addAttribute("password", password);
model.addAttribute("passwordError", str);
model.addAttribute("userError", str);
return "AdminLogin";
}
}
前端显示:
4、防止用户重复提交
private boolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
if(client_token==null){
return true;
}
//取出存储在Session中的token
String server_token = (String) request.getSession().getAttribute("token");
//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
if(server_token==null){
return true;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}
@RequestMapping("/insertInformation/{personId}")
public String insertInformation(@ModelAttribute information info,
@PathVariable String personId,
HttpServletRequest request,
Model model){
boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
if(b==true){
System.out.println("请不要重复提交");
}else {
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!!");
perService.InsertInfo(info, personId);
}
model.addAttribute("information", info);
person person = perService.selectPerson(personId);
model.addAttribute("name", person.getName());
model.addAttribute("personId", person.getPersonId());
model.addAttribute("message", "您今天已打卡成功!");
model.addAttribute("flag", 1);
return "inputInformation";
}
5、接入腾讯防水墙
<form id="form1" modelattribute="person" action="/userPage/login" method="post">
<div class="line"><span>账号:</span>
<input class="bt_input" type="text" name="personId" th:value="${personId}" required="">
</div>
<div class="line"><span>密码:</span>
<input class="bt_input" type="password" name="password" th:value="${password}" required="">
</div>
<!--点击此元素会自动激活验证码-->
<!--id : 元素的id(必须)-->
<!--data-appid : AppID(必须)-->
<!--data-cbfn : 回调函数名(必须)-->
<!--data-biz-state : 业务自定义透传参数(可选)-->
<input id="ticket" name="ticket" type="hidden" value="">
<input id="randStr" name="randStr" type="hidden" value="">
<button class="logingBut"
id="TencentCaptcha"
data-appid="1306253469"
data-cbfn="callback"
type="button"
onclick='submitFormWithCaptcha()'
>验证并登录</button>
</form>
function submitFormWithCaptcha() {
// 直接生成一个验证码对象
var captcha = new TencentCaptcha('1306253469', function (res) {
console.log(res)
// res(未通过验证)= {ret: 1, ticket: null}
// res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}
if (res.ret === 0) {
console.log("get form")
var form = document.getElementById('form1');
console.log("get ticket")
var ticketInput = document.getElementById("ticket");
console.log("get rnadstr")
var randstrInput = document.getElementById("randStr");
console.log(res.ticket)
ticketInput.value = res.ticket;
console.log("input randstr")
randstrInput.value = res.randstr;
console.log("submit")
form.submit();
}
else
{
console.log("验证失败")
alert("验证失败");
}
});
// 显示验证码
captcha.show();
}
6、打卡模块
//打卡
public void InsertInfo(information info, String personId){
QueryWrapper<person> wrapper = new QueryWrapper<>();
wrapper.eq("person_id", personId);
person per = perMapper.selectOne(wrapper);
info.setName(per.getName());
info.setPersonId(per.getPersonId());
info.setTime(LocalDateTime.now());
System.out.println(LocalDateTime.now());
infoMapper.insert(info);
}
//判断当前账号今天是否打卡过
public boolean is_clock_in(String personId){
QueryWrapper<information> wrapper = new QueryWrapper<>();
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateFormat = sdf.format(date);
//使用time进行模糊查询判断今天是否打卡过
wrapper.eq("person_id", personId);
wrapper.like("time", dateFormat);
information information = infoMapper.selectOne(wrapper);
if(information == null)
return false;
else return true;
}
@RequestMapping("/{personId}/inputInfo")
public String inputInfo(@PathVariable("personId") String personId,
HttpServletRequest request, Model model){
person person = perService.selectPerson(personId);
boolean flag = perService.is_clock_in(personId);
if(flag == true)
return "redirect:/userPage/insertInformation/" + personId;
model.addAttribute("name",person.getName());
model.addAttribute("personId",person.getPersonId());
model.addAttribute("information", new information());
model.addAttribute("flag",0);
String token = TokenProcessor.getInstance().makeToken();//创建令牌
request.getSession().setAttribute("token", token); //在服务器使用session保存token(令牌)
return "inputInformation";
}
private boolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
if(client_token==null){
return true;
}
//取出存储在Session中的token
String server_token = (String) request.getSession().getAttribute("token");
//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
if(server_token==null){
return true;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}
@RequestMapping("/insertInformation/{personId}")
public String insertInformation(@ModelAttribute information info,
@PathVariable String personId,
HttpServletRequest request,
Model model){
boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
if(b==true){
System.out.println("请不要重复提交");
}else {
request.getSession().removeAttribute("token");//移除session中的token
System.out.println("处理用户提交请求!!");
perService.InsertInfo(info, personId);
}
model.addAttribute("information", info);
person person = perService.selectPerson(personId);
model.addAttribute("name", person.getName());
model.addAttribute("personId", person.getPersonId());
model.addAttribute("message", "您今天已打卡成功!");
model.addAttribute("flag", 1);
return "inputInformation";
}
7、账号管理
1)显示所有账号:
@RequestMapping("/personList")
public String personList(Model model){
List<person> list =adminService.getAllPerson();
model.addAttribute("personList", list);
return "person";
}
2)编辑修改账号信息:
@RequestMapping("/editPerson/{personId}")
public String editPerson(@PathVariable String personId, Model model){
final person person = perService.selectPerson(personId);
model.addAttribute("person", person);
return "editPerson";
}
3)删除账号
@RequestMapping("/deletePerson/{personId}")
public String deletePerson(@PathVariable String personId){
adminService.deletePerson(personId);
return "redirect:/admin/personList";
}
4)新增管管理员:
@RequestMapping("/addAdmin")
public String addAdmin(@ModelAttribute person per, Model model){
int i = adminService.addAdmin(per);
if(i == 1){
return "redirect:/admin/personList";
}
else {
model.addAttribute("name",per.getName());
model.addAttribute("personId",per.getPersonId());
model.addAttribute("password",per.getPassword());
if(perService.selectPerson(per.getPersonId()).getFlag() == 0)
model.addAttribute("userExists",per.getPersonId() + "为普通用户\n可在列表编辑升级为管理员用户!");
else
model.addAttribute("userExists", per.getPersonId() + "用户已存在,并且是管理员用户");
return "inputAdmin";
}
}
8、数据查询
1)动态sql变量实体类
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class DynamicSql {
private String name;
private String personId;
private String latestTime;
private String laterTime;
private String identity;
private String health;
private String keyArea;
private String keyPeople;
private float temperature;
}
2)sql语句拼接
public List<information> selectByCondition(DynamicSql dynamicSql){
QueryWrapper<information> wrapper = new QueryWrapper<>();
if(dynamicSql.getName() != "")
wrapper.eq("name",dynamicSql.getName());
if (dynamicSql.getPersonId() != "")
wrapper.eq("person_id", dynamicSql.getPersonId());
if(dynamicSql.getLatestTime() != "" && dynamicSql.getLaterTime() !="")
wrapper.between("time", dynamicSql.getLatestTime(), dynamicSql.getLaterTime() + " 23:59:59");
if(dynamicSql.getIdentity() != "")
wrapper.eq("identity", dynamicSql.getIdentity());
if(dynamicSql.getHealth() != "")
wrapper.eq("health", dynamicSql.getHealth());
if(dynamicSql.getKeyArea() != "")
wrapper.eq("key_area", dynamicSql.getKeyArea());
if(dynamicSql.getKeyPeople() != "")
wrapper.eq("key_people", dynamicSql.getKeyPeople());
if (dynamicSql.getTemperature() != 0.0)
wrapper.ge("temperature", dynamicSql.getTemperature());
wrapper.orderByDesc("time");
List<information> lists = infoMapper.selectList(wrapper);
return lists;
}
@RequestMapping("/selectByCondition")
public String selectByCondition(@ModelAttribute DynamicSql dynamicSql, Model model){
List<information> informationList = adminService.selectByCondition(dynamicSql);
model.addAttribute("informationList", informationList);
model.addAttribute("dynamicSql", dynamicSql);
return "collection";
}
查出姓名为杨海林的6月15号到6月21号的打卡数据:
查出大一的打卡数据:
查出有咳嗽、发热症状的同学的打卡数据
等等,可进行多条件查询...
9、把数据导出Excel表格
@RequestMapping("/downloadInformation")
public String downloadInformation(@ModelAttribute DynamicSql dynamicSql, HttpServletResponse response, Model model) throws IOException {
HSSFWorkbook workbook = new HSSFWorkbook();
HSSFSheet sheet = workbook.createSheet("打卡信息表");
List<information> informationExcelDownloads = adminService.selectByCondition(dynamicSql);
String fileName = "information" + ".xls";
int rowNum = 1;
String [] headers = {"name", "person_id", "birthday", "CD_type", "CD_card", "identity",
"phone", "native_city", "home_address", "now_address", "health", "key_area", "key_people",
"temperature", "time"};
HSSFRow row = sheet.createRow(0);
for (int i = 0;i<headers.length;i++){
HSSFCell cell = row.createCell((short) i);
HSSFRichTextString text = new HSSFRichTextString(headers[i]);
cell.setCellValue(text);
}
for (information info : informationExcelDownloads){
HSSFRow row1 = sheet.createRow(rowNum);
row1.createCell((short) 0).setCellValue(new HSSFRichTextString(info.getName()));
row1.createCell((short) 1).setCellValue(new HSSFRichTextString(info.getPersonId()));
row1.createCell((short) 2).setCellValue(new HSSFRichTextString(info.getBirthday().toString()));
row1.createCell((short) 3).setCellValue(new HSSFRichTextString(info.getCdType()));
row1.createCell((short) 4).setCellValue(new HSSFRichTextString(info.getCdCard()));
row1.createCell((short) 5).setCellValue(new HSSFRichTextString(info.getIdentity()));
row1.createCell((short) 6).setCellValue(new HSSFRichTextString(info.getPhone()));
row1.createCell((short) 7).setCellValue(new HSSFRichTextString(info.getNativeCity()));
row1.createCell((short) 8).setCellValue(new HSSFRichTextString(info.getHomeAddress()));
row1.createCell((short) 9).setCellValue(new HSSFRichTextString(info.getNowAddress()));
row1.createCell((short) 10).setCellValue(new HSSFRichTextString(info.getHealth()));
row1.createCell((short) 11).setCellValue(new HSSFRichTextString(info.getKeyArea()));
row1.createCell((short) 12).setCellValue(new HSSFRichTextString(info.getKeyPeople()));
row1.createCell((short) 13).setCellValue(new HSSFRichTextString(String.valueOf(info.getTemperature())));
row1.createCell((short) 14).setCellValue(new HSSFRichTextString(String.valueOf(info.getTime()).replace('T', ' ')));
rowNum++;
}
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
response.flushBuffer();
workbook.write(response.getOutputStream());
return "redirect:/admin/personList";
}
查出姓名为HelenYang的数据并导出excel表:
相对应实体类:
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class person {
@TableId
private String personId; //学号、职工号
private String name; //姓名
private String password; //密码
private int flag;//标记为是否为管理员, 1为管理员, 0不是管理员
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class information {
private String name; //姓名
private String personId; //学号,职工号
private Date birthday; //出生日期
private String cdType; //证件类型
private String cdCard; //证件号码
private String phone; //联系电话
private String identity; //职业
private String nativeCity; //籍贯
private String homeAddress; //户口所在地
private String nowAddress; //现在居住地址
private String health; //健康状况
private String keyArea; //近14天是否到达过重点地区
private String keyPeople; //近14天是否接触过重点人群
private float temperature; //今日体温
private LocalDateTime time; //打卡时间
}
Dockerfile
将jar包和Dockerfile放到同一个目录下
Docker相关命令
docker build -t healthsystem . //构建healthsystem镜像
docker run -d -P --name healthsystem-test healthsystem //生成容器并后台运行
curl localhost:49153 //本机地址访问
Docker内部访问
构架镜像
后台启动服务
访问测试--测试成功
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。