一、实验目的
1.掌握软件开发的基本流程
2.掌握常用的软件开发方式和工具。
二、实验内容
设计一个包含登录界面的计算器软件,该软件可以实现第一次作业中的全部功能,同时使用数据库可以保存用户的历史计算记录和时间。
三、项目流程和功能
1.计算器的实现
2.登录网页版计算器
3.界面的注册登录功能
4.对使用者的账号密码信息进行保存
5.进行加减乘除开方运算并用数据库对这些数据进行精确地时间性保存
四、项目所需要的工具与环境
1.visio绘图工具
2.2021版Idea
3.MySQL5.5版本编写数据库
4.Navicat来连接MySQL
5.JDK.8.0_121
五、流程图
1.注册流程图
2.登录流程图
六、功能界面展示
1.登录界面
2.注册用户
3.登录计算
4.数据库展示
七、代码展示
1.用户的登录过程
1 package org.calculator.controller; 2 3 import org.calculator.entity.History; 4 import org.calculator.service.UserService; 5 import org.springframework.stereotype.Controller; 6 import org.springframework.web.bind.annotation.*; 7 8 import javax.annotation.Resource; 9 import javax.servlet.http.HttpServletRequest; 10 import java.util.HashMap; 11 import java.util.List; 12 import java.util.Map; 13 14 /** 15 * 用户控制器 16 * 17 * @author TianJiyuan 18 * @date 2023/11/20 19 */ 20 @Controller 21 @RestController 22 @ResponseBody 23 public class UserController { 24 @Resource 25 private UserService userService; 26 27 @PostMapping("login") 28 public Map<String, Object> login(HttpServletRequest request, @RequestParam("username") String username, @RequestParam("password") String password) { 29 Map<String, Object> result = new HashMap<String, Object>(); 30 result.put("code", 0); 31 String status = userService.login(request.getSession(), username, password); 32 if ("success".equals(status)) { 33 result.put("msg", "登录成功"); 34 } else { 35 result.put("code", 1); 36 result.put("msg", "用户名或密码错误"); 37 } 38 return result; 39 } 40 41 @PostMapping("signIn") 42 public Map<String, Object> signIn(@RequestParam("username") String username, @RequestParam("password") String password) { 43 Map<String, Object> result = new HashMap<String, Object>(); 44 result.put("code", 0); 45 46 String status = userService.signIn(username, password); 47 if ("success".equals(status)) { 48 result.put("msg", "登录成功"); 49 } else { 50 result.put("code", 1); 51 result.put("msg", "账号已存在"); 52 } 53 54 return result; 55 } 56 57 @PostMapping("saveHis") 58 public Map<String, Object> saveHis(HttpServletRequest request, @RequestParam("content") String content, @RequestParam("time") String time) { 59 Map<String, Object> result = new HashMap<String, Object>(); 60 result.put("code", 0); 61 String status = userService.saveHis(request.getSession(), content, time); 62 if ("success".equals(status)) { 63 result.put("msg", "保存成功"); 64 } else { 65 result.put("code", 1); 66 result.put("msg", "保存失败"); 67 } 68 return result; 69 } 70 71 @GetMapping("getHis") 72 public Map<String, Object> getHis(HttpServletRequest request) { 73 Map<String, Object> result = new HashMap<String, Object>(); 74 List<History> historyList = userService.getHis(request.getSession()); 75 result.put("code", 0); 76 result.put("data", historyList); 77 return result; 78 } 79 80 @GetMapping("logOut") 81 public String logOut(HttpServletRequest request) { 82 request.getSession().removeAttribute("login"); 83 return "success"; 84 } 85 }
2.用户账号的历史信息
1 package org.calculator.entity; 2 3 import com.baomidou.mybatisplus.annotation.TableId; 4 import com.baomidou.mybatisplus.annotation.TableName; 5 import lombok.Getter; 6 import lombok.Setter; 7 8 /** 9 * 历史 10 * 11 * @author TianJiyuan 12 * @date 2023/11/21 13 */ 14 @Getter 15 @Setter 16 @TableName 17 public class History { 18 @TableId 19 private String id; 20 21 private String username; 22 23 private String title; 24 25 private String time; 26 }
3.用户表
1 package org.calculator.entity; 2 3 import com.baomidou.mybatisplus.annotation.TableId; 4 import lombok.Getter; 5 import lombok.Setter; 6 7 import java.sql.Timestamp; 8 9 /** 10 * 用户表 11 * 12 * @author TianJiyuan 13 * @date 2023/11/20 14 */ 15 @Getter 16 @Setter 17 public class User { 18 @TableId 19 private String username; 20 21 private String password; 22 }
4.历史记录mapper
1 package org.calculator.mapper; 2 3 import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 import org.calculator.entity.History; 5 6 /** 7 * 历史记录mapper 8 * 9 * @author TianJiyuan 10 * @date 2023/11/21 11 */ 12 public interface HistoryMapper extends BaseMapper<History> { 13 }
5.用户Mapper
1 package org.calculator.mapper; 2 3 import com.baomidou.mybatisplus.core.mapper.BaseMapper; 4 import org.calculator.entity.User; 5 6 /** 7 * 用户Mapper 8 * 9 * @author TianJiyuan 10 * @date 2023/11/20 11 */ 12 public interface UserMapper extends BaseMapper<User> { 13 }
6.用户相关服务
1 package org.calculator.service; 2 3 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 4 import org.calculator.entity.History; 5 import org.calculator.entity.User; 6 import org.calculator.mapper.HistoryMapper; 7 import org.calculator.mapper.UserMapper; 8 import org.springframework.stereotype.Service; 9 10 import javax.annotation.Resource; 11 import javax.servlet.http.HttpSession; 12 import java.util.ArrayList; 13 import java.util.List; 14 15 /** 16 * 用户相关服务 17 * 18 * @author TianJiyuan 19 * @date 2023/11/20 20 */ 21 @Service 22 public class UserService { 23 @Resource 24 private UserMapper userMapper; 25 26 @Resource 27 private HistoryMapper historyMapper; 28 29 /** 30 * 注册 31 * 32 * @param username 用户名 33 * @param password 密码 34 * @return success | error 35 */ 36 public String signIn(String username, String password) { 37 User existUser = userMapper.selectById(username); 38 if (existUser != null) { 39 return "error"; 40 } 41 42 User user = new User(); 43 user.setUsername(username); 44 user.setPassword(password); 45 46 userMapper.insert(user); 47 48 return "success"; 49 } 50 51 /** 52 * 登录 53 * 54 * @param username 用户名 55 * @param password 密码 56 * @return success | error 57 */ 58 public String login(HttpSession session, String username, String password) { 59 User user = userMapper.selectById(username); 60 if (user == null) { 61 return "error"; 62 } 63 if (!user.getPassword().equals(password)) { 64 return "error"; 65 } 66 session.setAttribute("login", user); 67 68 return "success"; 69 } 70 71 /** 72 * 保存历史记录 73 * 74 * @param content 保存的内容 75 * @return success | error 76 */ 77 public String saveHis(HttpSession session, String content, String time) { 78 User user = (User) session.getAttribute("login"); 79 History history = new History(); 80 history.setTitle(content); 81 history.setTime(time); 82 history.setUsername(user.getUsername()); 83 historyMapper.insert(history); 84 return "success"; 85 } 86 87 /** 88 * 获取历史记录 89 * 90 * @param session session 91 * @return 历史记录列表 92 */ 93 public List<History> getHis(HttpSession session) { 94 User user = (User) session.getAttribute("login"); 95 List<History> historyList = historyMapper.selectList(new QueryWrapper<History>().eq("username", user.getUsername())); 96 if (historyList == null) { 97 return new ArrayList<History>(); 98 } 99 return historyList; 100 } 101 }
7.主函数
1 package org.calculator; 2 3 import org.mybatis.spring.annotation.MapperScan; 4 import org.springframework.boot.SpringApplication; 5 import org.springframework.boot.autoconfigure.SpringBootApplication; 6 7 @SpringBootApplication 8 @MapperScan("org.calculator.mapper") 9 public class CalculatorApplication { 10 11 public static void main(String[] args) { 12 SpringApplication.run(CalculatorApplication.class, args); 13 } 14 15 }
8.MySQL数据库对历史数据进行处理
1 /* 2 Navicat Premium Data Transfer 3 4 Source Server : localhost 5 Source Server Type : MySQL 6 Source Server Version : 50717 7 Source Host : localhost:3306 8 Source Schema : calculator 9 10 Target Server Type : MySQL 11 Target Server Version : 50717 12 File Encoding : 65001 13 14 Date: 21/11/2023 11:22:54 15 */ 16 17 SET NAMES utf8mb4; 18 SET FOREIGN_KEY_CHECKS = 0; 19 20 -- ---------------------------- 21 -- Table structure for history 22 -- ---------------------------- 23 DROP TABLE IF EXISTS `history`; 24 CREATE TABLE `history` ( 25 `id` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 26 `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 27 `title` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 28 `time` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 29 PRIMARY KEY (`id`) USING BTREE 30 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 31 32 -- ---------------------------- 33 -- Records of history 34 -- ---------------------------- 35 INSERT INTO `history` VALUES ('1726800603630477313', 'admin', '6-3 = 3', '2023/11/21 11:12:00'); 36 INSERT INTO `history` VALUES ('1726801184491290626', 'admin', '9*5 = 45', '2023/11/21 11:14:19'); 37 INSERT INTO `history` VALUES ('1726801234583863298', 'admin', '9*8 = 72', '2023/11/21 11:14:31'); 38 INSERT INTO `history` VALUES ('1726801318641909762', 'admin', '6+6+3 = 15', '2023/11/21 11:14:51'); 39 40 -- ---------------------------- 41 -- Table structure for user 42 -- ---------------------------- 43 DROP TABLE IF EXISTS `user`; 44 CREATE TABLE `user` ( 45 `username` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 46 `password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, 47 PRIMARY KEY (`username`) USING BTREE 48 ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; 49 50 -- ---------------------------- 51 -- Records of user 52 -- ---------------------------- 53 INSERT INTO `user` VALUES ('admin', '123456'); 54 55 SET FOREIGN_KEY_CHECKS = 1;
9.计算器的登录界面和对相关处理数据进行保存
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 <title>计算器</title> 8 <style> 9 * { 10 margin: 0; 11 padding: 0; 12 } 13 14 body { 15 width: 100%; 16 } 17 18 /* 登录部分 */ 19 20 .login { 21 position: absolute; 22 top: 50%; 23 left: 50%; 24 margin: -150px 0 0 -150px; 25 width: 300px; 26 height: 300px; 27 } 28 29 .login h1 { 30 color: #333; 31 letter-spacing: 2px; 32 text-align: center; 33 margin-bottom: 20px; 34 } 35 36 input { 37 line-height: 36px; 38 width: 100%; 39 margin-bottom: 10px; 40 border: 1px solid black; 41 border-radius: 5px; 42 letter-spacing: 2px; 43 padding: 0 10px; 44 box-sizing: border-box; 45 } 46 47 .form_b { 48 width: 100%; 49 display: flex; 50 justify-content: space-between; 51 } 52 53 .btn { 54 width: 46%; 55 padding: 10px; 56 background-color: #000; 57 color: #fff; 58 border: 1px solid black; 59 border-radius: 25px; 60 cursor: pointer; 61 margin-top: 10px; 62 } 63 64 /* 内容部分 */ 65 66 .content { 67 width: 100%; 68 display: flex; 69 } 70 71 .his_content { 72 width: 800px; 73 padding: 50px; 74 max-height: 100vh; 75 box-sizing: border-box; 76 } 77 78 .history { 79 height: 100%; 80 overflow-y: auto; 81 font-size: 30px; 82 } 83 84 .history_item { 85 display: flex; 86 justify-content: space-between; 87 padding: 10px; 88 color: #333; 89 border-bottom: 1px solid #f1f1f1; 90 } 91 92 .item_right { 93 font-size: 24px; 94 color: #666; 95 } 96 97 /*table部分*/ 98 99 table { 100 width: 460px; 101 height: 470px; 102 margin: 100px 180px; 103 } 104 105 table tr { 106 width: 100%; 107 height: 20%; 108 } 109 110 table tr td { 111 box-sizing: border-box; 112 width: 16.66%; 113 font-size: 20px; 114 color: #333; 115 text-align: center; 116 cursor: pointer; 117 box-shadow: 0px 0px 4px #666 inset; 118 } 119 120 table tr button { 121 width: 100%; 122 height: 100%; 123 outline: none; 124 background-color: transparent; 125 border: none; 126 font-size: 20px; 127 color: #333; 128 cursor: pointer; 129 } 130 131 table tr button:hover { 132 background: #ccc; 133 } 134 135 table td input { 136 width: 100%; 137 height: 100%; 138 background-color: transparent; 139 border: none; 140 outline: none; 141 cursor: pointer; 142 font-size: 20px; 143 color: #333; 144 text-align: right; 145 } 146 147 .login_out { 148 position: absolute; 149 top: 20px; 150 right: 50px; 151 cursor: pointer; 152 } 153 154 </style> 155 </head> 156 157 <body> 158 159 <div class="login_out" onclick="loginOut()"> 160 退出登录 161 </div> 162 163 <div class="login"> 164 <h1>计算器</h1> 165 <input id="userName" type="text" placeholder="请输入用户名"> 166 <input id="password" type="password" placeholder="请输入密码"> 167 <div class="form_b"> 168 <button class="btn" onclick="check(1)">注册</button> 169 <button class="btn" onclick="check(2)">登录</button> 170 </div> 171 </div> 172 173 <div class="content"> 174 <table id="calculator" onclick="result(event)"> 175 <tr> 176 <td colspan="6"> 177 <input type="text" class="contentValue"> 178 </td> 179 </tr> 180 <tr> 181 <td> 182 <button class="numb" value="1">1</button> 183 </td> 184 <td> 185 <button class="numb" value="2">2</button> 186 </td> 187 <td> 188 <button class="numb" value="3">3</button> 189 </td> 190 <td> 191 <button class="numb" value="+">+</button> 192 </td> 193 <td> 194 <button class="numb" value="C">C</button> 195 </td> 196 </tr> 197 <tr> 198 <td> 199 <button class="numb" svalue="4">4</button> 200 </td> 201 <td> 202 <button class="numb" value="5">5</button> 203 </td> 204 <td> 205 <button class="numb" value="6">6</button> 206 </td> 207 <td> 208 <button class="numb" value="-">-</button> 209 </td> 210 <td> 211 <button class="numb" value="Back">Back</button> 212 </td> 213 </tr> 214 215 <td> 216 <button class="numb" value="7">7</button> 217 </td> 218 <td> 219 <button class="numb" value="8">8</button> 220 </td> 221 <td> 222 <button class="numb" value="9">9</button> 223 </td> 224 <td> 225 <button class="numb" value="*">*</button> 226 </td> 227 <td rowspan="2"> 228 <button class="numb" value="=">=</button> 229 </td> 230 </tr> 231 <tr> 232 <td> 233 <button class="numb" value=".">.</button> 234 </td> 235 <td> 236 <button class="numb" value="0">0</button> 237 </td> 238 <td> 239 <button class="numb" value="/">/</button> 240 </td> 241 <td> 242 <button class="numb">√x</button> 243 </td> 244 </tr> 245 </table> 246 247 <div class="his_content"> 248 <h1>历史记录</h1> 249 <div class="history"> 250 251 </div> 252 </div> 253 </div> 254 255 <script> 256 let record = []; 257 258 function getRecord() { 259 $.ajax({ 260 url: 'getHis', 261 type: 'GET', 262 dataType: 'json', 263 success: function (response) { 264 if (response.code === 0) { 265 // 接口成功后 266 record = response.data; 267 historyShow() 268 } else { 269 alert(response.msg); 270 } 271 } 272 }); 273 } 274 275 window.onload = function () { 276 let login = localStorage.getItem("login"); 277 document.querySelector('.contentValue').value = '' 278 document.querySelector('#userName').value = '' 279 document.querySelector('#password').value = '' 280 if (login == 'true') { 281 document.querySelector('.login').style.display = 'none'; 282 getRecord() 283 } else { 284 document.querySelector('.content').style.display = 'none' 285 document.querySelector('.login_out').style.display = 'none' 286 } 287 } 288 289 // 校验信息 290 function check(type) { 291 let userName = document.querySelector('#userName').value 292 let password = document.querySelector('#password').value 293 if (userName && password) { 294 let params = { 295 userName, 296 password 297 } 298 if (type == 1) { 299 // 注册接口 300 register(params) 301 } else { 302 // 登录接口 303 login(params) 304 } 305 } else { 306 alert('请输入完整'); 307 return; 308 } 309 } 310 311 // 登录 312 function login(params) { 313 $.ajax({ 314 url: '/login', 315 type: 'POST', 316 dataType: 'json', 317 data: { 318 username: params.userName, 319 password: params.password, 320 }, 321 success: function (response) { 322 if (response.code === 0) { 323 // 接口成功后 324 localStorage.setItem("login", true) 325 localStorage.setItem("username", params.userName) 326 document.querySelector('.login').style.display = 'none' 327 document.querySelector('.content').style.display = 'flex' 328 document.querySelector('.login_out').style.display = 'block' 329 document.querySelector('#userName').value = '' 330 document.querySelector('#password').value = '' 331 getRecord(); 332 historyShow(); 333 } else { 334 alert(response.msg); 335 } 336 } 337 }); 338 } 339 340 // register 341 function register(params) { 342 $.ajax({ 343 url: 'signIn', 344 type: 'POST', 345 dataType: 'json', 346 data: { 347 username: params.userName, 348 password: params.password, 349 }, 350 success: function (response) { 351 if (response.code === 0) { 352 alert("注册成功"); 353 // 接口成功后 354 document.querySelector('#userName').value = '' 355 document.querySelector('#password').value = '' 356 } else { 357 alert(response.msg); 358 } 359 } 360 }); 361 362 } 363 364 // 添加到数据库 365 function addRecord(obj) { 366 let params = { 367 content: obj.title, 368 time: obj.time 369 } 370 $.ajax({ 371 url: '/saveHis', 372 type: 'POST', 373 dataType: 'json', 374 data: params, 375 success: function (response) { 376 if (response.code !== 0) { 377 alert(response.msg); 378 } 379 } 380 }); 381 } 382 383 // 计算功能 384 function result(e) { 385 //获取触发事件的元素 386 //利用e.target||e.srcElement,获取到触发事件的元素,||连接两个语法是为了解决不同浏览器的兼容性问题。 387 var obj = e.target || e.srcElement; 388 if (obj.nodeName != "BUTTON") { 389 return; 390 } 391 var v = obj.innerHTML; 392 var content = document.querySelector('.contentValue'); 393 if (v === "C") { 394 content.value = 0; 395 } else if (v === "=") { 396 //获取到输入框的值 397 var exp = content.value; 398 //这里用try catch抛出异常,针对运算错误的情况 399 try { 400 let timer = new Date() 401 let obj = { 402 title: exp, 403 time: timer.toLocaleString() 404 } 405 var result = eval("(" + exp + ")"); 406 //将计算结果赋值给输入框 407 content.value = result; 408 409 // 更新历史数据 410 obj.title = obj.title + ' = ' + result 411 record.push(obj) 412 addRecord(obj) 413 historyShow() 414 } catch (e) { 415 console.log(e); 416 content.value = "error"; 417 } 418 } else if (v === "√x") { 419 let timer = new Date() 420 let obj = { 421 title: '√' + content.value, 422 time: timer.toLocaleString() 423 } 424 var result = mysqrt(content.value); 425 content.value = result; 426 427 // 更新历史数据 428 obj.title = obj.title + ' = ' + result 429 record.push(obj) 430 addRecord(obj) 431 historyShow() 432 433 } else if (v === "Back") { 434 var str = content.value; 435 var result = str.substring(0, str.length - 1); 436 content.value = result; 437 } else { 438 if (content.value === "0") 439 content.value = " "; 440 content.value += v; 441 } 442 } 443 444 // 开方 445 function mysqrt(x) { 446 r = x; 447 while (r * r > x) { 448 r = (r + x / r) / 2 449 } 450 return r 451 } 452 453 // 历史数据渲染 454 function historyShow() { 455 let listStr = '' 456 457 record.forEach(item => { 458 listStr += ` 459 <div class="history_item"> 460 <div class="item_left"> 461 ${item.title} 462 </div> 463 <div class="item_right"> 464 ${item.time} 465 </div> 466 </div> 467 ` 468 }) 469 document.querySelector('.history').innerHTML = listStr 470 } 471 472 function loginOut() { 473 localStorage.setItem("login", false) 474 location.reload(); 475 } 476 </script> 477 </body> 478 479 </html>
10.连接本地数据库进行网页登录
1 server: 2 port: 8081 3 spring: 4 application: 5 name: calculator 6 datasource: 7 url: jdbc:mysql://localhost:3306/calculator?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false 8 type: com.zaxxer.hikari.HikariDataSource 9 driver-class-name: com.mysql.cj.jdbc.Driver 10 username: root 11 password: 123456 12 hikari: 13 connection-test-query: SELECT 1 14 connection-timeout: 30000 15 validation-timeout: 10000 16 idle-timeout: 600000 17 max-lifetime: 120000 18 maximum-pool-size: 50 19 minimum-idle: 10