学习视频:【编程不良人】2021年SpringBoot最新最全教程
第十章、项目开发
实现一个登录注册,增删改查功能的系统
10.1 项目开发流程
- 需求分析
分析用户主要需求 提取项目核心功能,根据核心功能构建页面原型
- 库表设计:
- 详细设计(流程图、伪代码):
验证库表准确性
- 功能实现(编码)
环境搭建,具体功能实现
- 功能测试,部署,上线,运维,维护
全栈式开发:前端+后端+运维
10.2 需求分析
- 系统有哪些模块?
- 每个模块功能有哪些?
- 用户模块:登录、注册、验证码生成
- 员工模块:查询、删除、更新、添加
10.3 库表设计
用户表:user
员工表:employee
表与表关系:user,employee 独立两张表
创建库表- create database ems;
- use ems;
- create TABLE user(
- id int auto_increment ,username VARCHAR(40) COMMENT '用户名' ,
- realname VARCHAR(40) COMMENT '真实姓名' ,
- `password` VARCHAR(50) COMMENT '密码',gender TINYINT(3) COMMENT '性别',
- PRIMARY KEY (`id`)
- );
- create TABLE employee(
- id int auto_increment,
- name VARCHAR(40) COMMENT '姓名',
- birthday datetime COMMENT '生日',
- salary DOUBLE COMMENT '薪资',
- gender TINYINT(3) COMMENT '性别',
- PRIMARY KEY(id)
- )
复制代码 10.5 编码环节
技术选型:SpringBoot + MyBatis + JSP + MySQL
环境搭建:Spring Boot + JSP + MyBatis
创建名为ems-jsp的项目,并引入web支持依赖,创建完成

环境搭建
pom.xml依赖导入- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>org.apache.tomcat.embed</groupId>
- <artifactId>tomcat-embed-jasper</artifactId>
- </dependency>
-
-
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.19</version>
- </dependency>
-
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>3.0.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- </dependency>
- </dependencies>
复制代码 application.yml:- # 应用服务 WEB 访问端口
- server:
- port: 8989
- servlet:
- context-path: /ems-jsp
- jsp:
- init-parameters:
- development: true # 开启jsp模板开发模式
- # 配置jsp展示
- spring:
- mvc:
- view:
- prefix: /
- suffix: .jsp
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://localhost:3306/ems?characterEncoding=UTF-8
- username: root
- password: 123456
- # 配置mybatis
- mybatis:
- mapper-locations: classpath:com.baizhi/mapper/*.xml
- type-aliases-package: com.baizhi.entity
- # 配置日志
- logging:
- level:
- com.baizhi: debug
复制代码 添加dao包扫描- @SpringBootApplication
- @MapperScan("com.baizhi.dao")
- public class EmsJspApplication {
- public static void main(String[] args) {
- SpringApplication.run(EmsJspApplication.class, args);
- }
- }
复制代码 10.6 验证码实现
- 业务逻辑
- 生成随机字符(依靠工具类VerifyCode)
- 放入session(与前端传过来的验证码进行比对),放进map(传给前端)
- 生成图片响应
- register.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Registration Page</title>
- <link rel="stylesheet" type="text/css" href="css/register.css">
- </head>
- <body>
- <h2>用户注册</h2>
- <h3 >${param.msg}</h3>
- <form action="${pageContext.request.contextPath}/user/register" method="post">
- 用户名: <input type="text" name="username"><br>
- 真实姓名: <input type="text" name="realname" ><br>
- 密码: <input type="password" name="password" ><br>
- <%-- 确认密码: <input type="password" name="confirmPassword"><br>--%>
- 性别:
- <select name="gender" >
- <option value="1">男</option>
- <option value="0">女</option>
- </select><br>
-
- <label for="verifyCode">验证码:</label><br>
- <img id="verifyCode" src="" alt="Captcha Image">
- <a target="_blank" href="https://www.cnblogs.com/javascript:" id="refresh">换一张</a>
- <input type="text" name="code"><br>
- <input type="submit" value="注册">
- </form>
- </body>
- </html>
复制代码 - css
- body {
- font-family: 'Arial', sans-serif;
- margin: auto;
- justify-content: center;
- align-items: center;
- width: 500px;
- height: 800px;
- /*border: 1px solid red;*/
- }
- .container {
- padding: 30px;
- background-color: #ffffff;
- border-radius: 8px;
- box-shadow: 0 0 15px rgba(0, 0, 0, 0.1);
- /*border: 1px solid red;*/
- }
- h2 {
- text-align: center;
- }
- input[type="text"],
- input[type="password"],
- input[type="submit"],
- select {
- width: calc(100% - 20px);
- margin-bottom: 15px;
- padding: 10px;
- border: 1px solid #dddddd;
- border-radius: 5px;
- transition: border-color 0.3s ease-in-out;
- }
- input[type="text"]:focus,
- input[type="password"]:focus,
- select:focus {
- outline: none;
- border-color: #66afe9;
- }
- input[type="submit"] {
- background-color: #4CAF50;
- color: white;
- border: none;
- cursor: pointer;
- transition: background-color 0.3s ease-in-out;
- }
- input[type="submit"]:hover {
- background-color: seagreen;
- }
复制代码 - 验证码 实现类
- package com.baizhi.utils;
- import javax.imageio.ImageIO;
- import java.awt.Color;
- import java.awt.Font;
- import java.awt.Graphics;
- import java.awt.image.BufferedImage;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.Random;
- public class VerifyCode {
- private int width = 100;// 定义图片的width
- private int height = 40;// 定义图片的height
- private int codeCount = 4;// 定义图片上显示验证码的个数
- private int lineCount = 20;// 定义图片上显示干扰线的条数
- private String code = null;// 定义用于保存验证码的字符串
- private BufferedImage buffImg = null;// 定义图片Buffer
- private char[] codeSequence = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R',
- 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
- public VerifyCode() {
- this.createCode();
- }
- /**
- * @param width
- * 图片宽
- * @param height
- * 图片高
- */
- public VerifyCode(int width, int height) {
- this.width = width;
- this.height = height;
- this.createCode();
- }
- /**
- * @param width
- * 图片宽
- * @param height
- * 图片高
- * @param codeCount
- * 字符个数
- * @param lineCount
- * 干扰线条数
- */
- public VerifyCode(int width, int height, int codeCount, int lineCount) {
- this.width = width;
- this.height = height;
- this.codeCount = codeCount;
- this.lineCount = lineCount;
- this.createCode();
- }
- public void createCode() {
- int x = 0, fontHeight = 0, codeY = 0;
- int red = 0, green = 0, blue = 0;
- x = width / (codeCount + 2);// 每个字符的宽度
- fontHeight = height - 2;// 字体的高度
- codeY = height - 4;
- // 图像buffer
- buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics g = buffImg.createGraphics();
- // 创建一个随机数生成器类
- Random random = new Random();
- // 将图像填充为白色
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, width, height);
- // 创建字体,字体的大小应该根据图片的高度来定。
- Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
- // 设置字体。
- g.setFont(font);
- for (int i = 0; i < lineCount; i++) {
- // 设置随机开始和结束坐标
- int xs = random.nextInt(width);// x坐标开始
- int ys = random.nextInt(height);// y坐标开始
- int xe = xs + random.nextInt(width / 8);// x坐标结束
- int ye = ys + random.nextInt(height / 8);// y坐标结束
- // 生成随机颜色
- red = random.nextInt(255);
- green = random.nextInt(255);
- blue = random.nextInt(255);
- g.setColor(new Color(red, green, blue));
- g.drawLine(xs, ys, xe, ye);
- }
- // randomCode记录随机产生的验证码
- StringBuffer randomCode = new StringBuffer();
- // 随机产生codeCount个字符的验证码。
- for (int i = 0; i < codeCount; i++) {
- // 得到随机产生的验证码数字。
- String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
- // 用随机产生的颜色将验证码绘制到图像中。
- red = random.nextInt(255);
- green = random.nextInt(255);
- blue = random.nextInt(255);
- g.setColor(new Color(red, green, blue));
- g.drawString(strRand, (i + 1) * x, codeY);
- // 将产生的四个随机数组合在一起。
- randomCode.append(strRand);
- }
- // 将四位数字的验证码保存到Session中。
- code = randomCode.toString();
- }
- public void write(String path) throws IOException {
- OutputStream sos = new FileOutputStream(path);
- this.write(sos);
- }
- public void write(OutputStream sos) throws IOException {
- ImageIO.write(buffImg, "png", sos);
- sos.close();
- }
- public BufferedImage getBuffImg() {
- return buffImg;
- }
- public String getCode() {
- return code;
- }
- }
复制代码 - 验证码生成 请求
- @Controller
- @RequestMapping("user")
- public class UserController {
- /**
- * 生成验证码
- */
- @ResponseBody
- @RequestMapping("verifyCode")
- public Map<String, String> verifyCode(HttpServletRequest request) throws IOException {
- Map<String,String> map = new HashMap<>();
- // 1.使用工具类生成验证码
- VerifyCode vc = new VerifyCode(120, 40, 4, 100);
- String code = vc.getCode();
- map.put("code", code);
- // 2. 获取验证码的BufferedImage对象
- BufferedImage captchaImage = vc.getBuffImg();
- //4.将图片转为base64 [放入src,可以直接显示图片]
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- ImageIO.write(captchaImage, "png", outputStream);
- byte[] imageBytes = outputStream.toByteArray();
- String image = "data:image/png;base64," + Base64Utils.encodeToString(imageBytes);
- map.put("image", image);
- return map;
- }
- }
复制代码 10.7 注册实现
- 业务逻辑

- Service
- @Service
- @Transactional
- public class UserServiceImpl implements UserService {
- @Autowired
- private UserDao userDao;
- @Override
- public void register(User user) {
- User userDB = userDao.findByUserName(user.getUsername());
- if (!ObjectUtils.isEmpty(userDB)) {
- throw new RuntimeException("用户名已存在");
- }
- // 注册之前给密码进行加密
- String passwordSecret = DigestUtils.md5DigestAsHex(user.getPassword().getBytes(StandardCharsets.UTF_8));
- user.setPassword(passwordSecret);
- userDao.save(user);
- }
- }
复制代码 - mapper语句
- <select id="findByUserName" resultType="com.baizhi.entity.User">
- select id,username,realname,password,gender from `user`
- where username = #{username}
- </select>
复制代码 - api
- @Autowired
- private UserService userService;
- @RequestMapping("register")
- public String register(User user, String code, HttpSession session) {
- log.debug("接受的验证码:{}", code);
- log.debug("User:{}", user);
- // 比较验证
- try {
- String sessionCode = session.getAttribute("code").toString();
- if (!sessionCode.equalsIgnoreCase(code)) {
- throw new RuntimeException("验证码输入错误!!!");
- }
- userService.register(user);
- } catch (RuntimeException e) {
- e.printStackTrace();
- return "redirect:/register.jsp?msg=" + UriEncoder.encode(e.getMessage());
- }
- return "redirect:/login.jsp";
- }
复制代码 10.8用户登录

- login.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Login Page</title>
- <link rel="stylesheet" href="css/register.css">
- </head>
- <body>
- <h2>用户登录</h2>
- <h3 >${param.msg}</h3>
- <form action="${pageContext.request.contextPath}/employee/list" method="post">
- <label for="username">用户名:</label><br>
- <input type="text" id="username" name="username"><br>
- <label for="password">密码:</label><br>
- <input type="password" id="password" name="password"><br>
- <input type="submit" value="登录">
- <input type="button" onclick="window.location.href='register.jsp'" value="注册">
- </form>
- </body>
- </html>
复制代码 - ServiceImpl
- @Override
- public User login(String username, String password) {
- //1. 根据用户名查询数据库是否存在
- User user = userDao.findByUserName(username);
- //2.判断对象是否存在
- if (ObjectUtils.isEmpty(user)) {
- throw new RuntimeException("用户名输入错误!");
- }
- //3.判断密码正确性
- String digestPassword = DigestUtils.md5DigestAsHex(password.getBytes(StandardCharsets.UTF_8));
- if (!user.getPassword().equals(digestPassword)) {
- throw new RuntimeException("密码错误!");
- }
- return user;
- }
复制代码 - UserController
- @RequestMapping("login")
- public String login(String username, String password,HttpSession session) throws UnsupportedEncodingException {
- log.debug("接受到的用户名:{},接收到的密码:{}", username, password);
- try {
- // 1.执行登录业务逻辑
- User user = userService.login(username, password);
- // 2.登录成功,保存用户信息
- session.setAttribute("user", user);
- } catch (Exception e) {
- e.printStackTrace();
- return "redirect:/login.jsp?msg=" + UriEncoder.encode(e.getMessage());
- }
- return "redirect:/emplist.jsp";
- }
复制代码 10.9 员工列表展示
- emplist.jsp
- <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
- <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" %>
- <!DOCTYPE html>
- <html>
- <head>
- <title>用户列表</title>
- <link rel="stylesheet" href="${pageContext.request.contextPath}/css/emplist.css">
- </head>
- <body>
-
- <h2>用户列表</h2>
- <table>
- <tr>
- <th>ID</th>
- <th>姓名</th>
- <th>性别</th>
- <th>薪水</th>
- <th>生日</th>
- <th>操作</th>
- </tr>
- <c:forEach var="employee" items="${requestScope.employees}">
- <tr>
- <td>${employee.id}</td>
- <td>${employee.name}</td>
- <td>${employee.gender?'男':'女'}</td>
- <td>${employee.salary}</td>
- <td><fmt:formatDate value="${employee.birthday}" pattern="yyyy-MM-dd"/></td>
- <td>
- <a target="_blank" href="https://www.cnblogs.com/javascript:;">删除</a>
- <a target="_blank" href="https://www.cnblogs.com/javascript:;">修改</a>
- </td>
- </tr>
- </c:forEach>
- </table>
- <a target="_blank" href="https://www.cnblogs.com/javascript:;">添加员工信息</a>
-
- </body>
- </html>
复制代码 - emplist.css
- body {
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- }
- #container {
- max-width: 800px;
- margin: 0 auto;
- padding: 20px;
- }
- h2 {
- text-align: center;
- }
- table {
- width: 100%;
- border-collapse: collapse;
- margin-bottom: 20px;
- }
- th, td {
- padding: 10px;
- text-align: left;
- border: 1px solid #ccc;
- }
- thead {
- background-color: #f2f2f2;
- }
- div > button {
- margin: 5px;
- padding: 5px 10px;
- border: none;
- background-color: #007bff;
- color: #fff;
- cursor: pointer;
- }
- div > button:hover {
- background-color: #0056b3;
- }
- select, button {
- padding: 5px;
- }
- div > span {
- margin: 0 10px;
- font-weight: bold;
- }
- label {
- font-weight: bold;
- }
复制代码 - Service
- @Service
- @Transactional
- public class EmployeeServiceImpl implements EmployeeService {
- private final EmployeeDao employeeDao;
- @Autowired
- public EmployeeServiceImpl(EmployeeDao employeeDao) {
- this.employeeDao = employeeDao;
- }
- @Override
- public List<Employee> list() {
- return employeeDao.list();
- }
- }
复制代码 - EmployeeController
- @Controller
- @RequestMapping("employee")
- public class EmployeeController {
- private EmployeeService employeeService;
- @Autowired
- public EmployeeController(EmployeeService employeeService) {
- this.employeeService = employeeService;
- }
- /**
- * 员工列表
- *
- * @return
- */
- @RequestMapping("list")
- public String listEmployee(HttpServletRequest request, Model model) {
- //1. 获取员工列表
- List<Employee> employees = employeeService.list();
- // request.setAttribute("employees", employees);
- model.addAttribute("employees", employees);
- return "emplist";
- }
- }
复制代码 10.10 添加员工信息
- 在EmplyeeController开发一个添加方法
- 接收员工信息
- 将员工信息保存到数据库
- 跳转到员工列表展示数据
- addEmp.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" %>
- <!DOCTYPE html>
- <html>
- <head>
- <title>添加员工</title>
- <link rel="stylesheet" href="css/addEmp.css">
- </head>
- <body>
- <h2>添加员工</h2>
-
- <form action="${pageContext.request.contextPath}/employee/add" method="post">
- <table>
- <tr>
- <td>姓名:</td>
- <td><input type="text" id="name" name="name"></td>
- </tr>
- <tr>
- <td>薪水:</td>
- <td><input type="text" id="salary" name="salary"></td>
- </tr>
- <tr>
- <td>生日:</td>
- <td><input type="text" id="birthday" name="birthday"></td>
- </tr>
- <tr>
- <td>性别:</td>
- <td>
- <select name="gender" >
- <option value="1">男</option>
- <option value="0">女</option>
- </select>
- </td>
- </tr>
- <tr>
- <td colspan="2"><input type="submit" value="添加"></td>
- </tr>
- </table>
- </form>
-
- </body>
- </html>
复制代码 - addEmp.css
- body {
- font-family: Arial, sans-serif;
- margin: 0;
- padding: 0;
- }
- #container {
- max-width: 800px;
- margin: 0 auto;
- padding: 20px;
- }
- h2 {
- text-align: center;
- }
- table {
- width: 100%;
- border-collapse: collapse;
- margin-bottom: 20px;
- color: #212529;
- }
- td, th {
- vertical-align: top;
- padding: 10px;
- text-align: left;
- border: 1px solid #ccc;
- }
- input[type="text"], input[type="date"], select {
- width: 60%;
- padding: .375rem .75rem;
- border: 1px solid #ced4da;
- border-radius: .25rem;
- }
- input[type="submit"] {
- color: #fff;
- background-color: #007bff;
- border-color: #007bff;
- padding: .375rem .75rem;
- border-radius: .25rem;
- }
复制代码 - EmployeeDaomapper.xml
- <insert id="add" parameterType="Employee" useGeneratedKeys="true" keyProperty="id">
- INSERT INTO `ems`.`employee`(`id`, `name`, `birthday`, `salary`, `gender`) VALUES (#{id},#{name},#{birthday},#{salary},#{gender});
- </insert>
复制代码 - EmployeeServiceImpl
- public void addEmployee(Employee employee) {
- employeeDao.add(employee);
- }
复制代码 - Controller
- @RequestMapping("add")
- public String addEmployee(Employee employee) {
- log.debug("员工信息:{}", employee);
- //1. 保存员工信息
- employeeService.addEmployee(employee);
- return "redirect:/employee/list";
- }
复制代码 10.11 更新员工信息
- 显示员工信息
- 根据id查询员工信息
- 将对象放进作用域
- 跳转到更新页面
- UpdateEmp.jsp
- <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8" %>
- <!DOCTYPE html>
- <html>
- <head>
- <title>修改员工信息</title>
- <link rel="stylesheet" href="${pageContext.request.contextPath}/css/updateEmp.css">
- </head>
- <body>
-
- <h2>修改员工信息</h2>
- <form action="${pageContext.request.contextPath}/employee/update" method="post">
- <input type="text" id="id" name="id" value="${employee.id}" >
- <label for="name">姓名:</label><br>
- <input type="text" id="name" name="name" value="${employee.name}"><br>
- <label for="gender">性别:</label><br>
- <select id="gender" name="gender">
- <option value="1" ${employee.gender?'selected':''}>男</option>
- <option value="0" ${!employee.gender?'selected':''}>女</option>
- </select><br>
- <label for="salary">薪水:</label><br>
- <input type="text" id="salary" name="salary" value="${employee.salary}"><br>
- <label for="birthday">生日:</label><br>
- <input type="text" id="birthday" name="birthday" value="<fmt:formatDate value='${employee.birthday}' pattern='yyyy/MM/dd'/>"/><br>
- <input type="submit" value="提交">
- </form>
-
- </body>
- </html>
复制代码 - UpdateEmp.css
- body {
- font-family: Arial, sans-serif;
- }
- #container {
- width: 300px;
- margin: 0 auto;
- padding: 20px;
- border: 1px solid #ccc;
- border-radius: 5px;
- background-color: #f8f8f8;
- }
- h2 {
- text-align: center;
- color: #333;
- }
- label {
- font-weight: bold;
- color: #555;
- }
- input[type="text"], input[type="date"],select {
- width: 70%;
- padding: 10px;
- margin: 5px 0 15px;
- border: 1px solid #ccc;
- border-radius: 3px;
- }
- input[type="submit"] {
- width: 100%;
- padding: 10px;
- color: white;
- background-color: #007BFF;
- border: none;
- border-radius: 3px;
- cursor: pointer;
- }
- input[type="submit"]:hover {
- background-color: #0056b3;
- }
复制代码 - Controller
- @RequestMapping("detail")
- public String detailEmployee(Integer id, Model model) {
- log.debug("接收的id:{}",id);
- Employee employee = employeeService.idByEmployee(id);
- model.addAttribute("employee", employee);
- return "updateEmp";
- }
复制代码 - 更改员工信息
- Controller
- @RequestMapping("update")
- public String updateEmployee(Employee employee) {
- log.debug("修改的员工信息:{}", employee);
- employeeService.updateEmployee(employee);
- return "redirect:/employee/list";
- }
复制代码 10.12 删除员工
- 传递id给后端进行数据库删除
- 返回employee/list重新查数据库刷新
- emplist.jsp
- <a target="_blank" href="https://www.cnblogs.com/javascript:;" onclick="deleteEmployee()">删除</a>
-
复制代码 - Controller
- @RequestMapping("delete")
- public String deleteEmployee(Integer id) {
- log.debug("接收的id:{}", id);
- employeeService.deleteEmployee(id);
- return "redirect:/employee/list";
- }
复制代码 - mapper
- <delete id="deleteEmployee">
- delete from `employee`where id =#{id}
- </delete>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |