学习视频:【编程不良人】2021年SpringBoot最新最全教程

第十章、项目开发

实现一个登录注册,增删改查功能的系统

10.1 项目开发流程

  1. 需求分析

    分析用户主要需求 提取项目核心功能,根据核心功能构建页面原型

  2. 库表设计:

    1. 分析系统有哪些表
    2. 分析表之间关联关系
    3. 确定字段
  3. 详细设计(流程图、伪代码):

    验证库表准确性

  4. 功能实现(编码)

    环境搭建,具体功能实现

  5. 功能测试,部署,上线,运维,维护

全栈式开发:前端+后端+运维

10.2 需求分析

  1. 系统有哪些模块?
  2. 每个模块功能有哪些?
    1. 用户模块:登录、注册、验证码生成
    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依赖导入

            org.springframework.boot        spring-boot-starter-web                org.springframework.boot        spring-boot-starter-test        test                    org.apache.tomcat.embed        tomcat-embed-jasper                        com.alibaba        druid        1.1.19                    mysql        mysql-connector-java                    org.mybatis.spring.boot        mybatis-spring-boot-starter        3.0.0                    org.springframework.boot        spring-boot-devtools    

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# 配置mybatismybatis:  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 验证码实现

  • 业务逻辑

    1. 生成随机字符(依靠工具类VerifyCode)
    2. 放入session(与前端传过来的验证码进行比对),放进map(传给前端)
    3. 生成图片响应
  • register.jsp

            Registration Page    

    用户注册

    ${param.msg}

    用户名:
    真实姓名:
    密码:
    <%-- 确认密码:
    --%> 性别: 男 女

    Captcha Image 换一张
    // jQuery代码 $(document).ready(function() { $('#registerForm').submit(function() { return validateRegisterForm(); }); }); // 表单验证 function validateRegisterForm() { var username = $('#username').val(), password = $('#password').val(), // confirmPassword = $('#confirmPassword').val(), realname = $('#realname').val(), code = $('#code').val(); console.log(backCode,code) if (username === "" || password === "" || realname === "" || code === "") { alert("请填写所有字段和验证码"); return false; } if (backCode.toLowerCase() === code.toLowerCase()) { alert("验证码填写不正确") refreshVerifyCode();// 刷新验证码 return false; } // if (password !== confirmPassword) { // alert("密码不匹配"); // return false; // } alert("注册成功,请登录") return true; } var backCode = ""; // 验证码刷新 function refreshVerifyCode() { $.ajax({ url: '${pageContext.request.contextPath}/user/verifyCode', method: 'GET', dataType: 'json', success: function(data) { console.log(data) backCode = data.code; $('#verifyCode').attr('src', data.image); }, error: function(error) { console.error('error:', error); } }); } // 初始化页面加载时显示验证码 refreshVerifyCode(); // 点击“换一张”按钮时刷新验证码 $('#refresh').click(function() { refreshVerifyCode(); });
  • 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 verifyCode(HttpServletRequest request) throws IOException {        Map 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@Transactionalpublic 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,username,realname,password,gender from `user`    where username = #{username}
  • api

    @Autowiredprivate 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

            Login Page    

    用户登录

    ${param.msg}





  • ServiceImpl

    @Overridepublic 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 员工列表展示

  1. 在数据库查询所有员工信息
  2. 在页面中进行展示
  • emplist.jsp

        用户列表        

    用户列表

    ID 姓名 性别 薪水 生日 操作
    ${employee.id} ${employee.name} ${employee.gender?'男':'女'} ${employee.salary} 删除 修改
    添加员工信息
  • 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@Transactionalpublic class EmployeeServiceImpl implements EmployeeService {    private final EmployeeDao employeeDao;    @Autowired    public EmployeeServiceImpl(EmployeeDao employeeDao) {        this.employeeDao = employeeDao;    }    @Override    public List 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 employees = employeeService.list();//        request.setAttribute("employees", employees);        model.addAttribute("employees", employees);        return "emplist";    }}

10.10 添加员工信息

  1. 在EmplyeeController开发一个添加方法
  2. 接收员工信息
  3. 将员工信息保存到数据库
  4. 跳转到员工列表展示数据
  • addEmp.jsp

        添加员工        

    添加员工

    姓名:
    薪水:
    生日:
    性别: 男 女
  • 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 INTO `ems`.`employee`(`id`, `name`, `birthday`, `salary`, `gender`) VALUES (#{id},#{name},#{birthday},#{salary},#{gender});
  • 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 更新员工信息

  • 显示员工信息

    1. 根据id查询员工信息
    2. 将对象放进作用域
    3. 跳转到更新页面
  • UpdateEmp.jsp

        修改员工信息        

    修改员工信息




    男 女



    <input type="text" name="birthday" value=""/>
  • 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";}
  • 更改员工信息

    1. 获取更新后的员工信息
    2. 更新数据库
  • Controller

    @RequestMapping("update")public String updateEmployee(Employee employee) {    log.debug("修改的员工信息:{}", employee);    employeeService.updateEmployee(employee);    return "redirect:/employee/list";}

10.12 删除员工

  1. 传递id给后端进行数据库删除
  2. 返回employee/list重新查数据库刷新
  • emplist.jsp

    删除      function deleteEmployee(){         if (window.confirm('确定删除这条记录吗')) {             location.href= '${pageContext.request.contextPath}/employee/delete?id=${employee.id}'         }     } 
  • Controller

    @RequestMapping("delete")public String deleteEmployee(Integer id) {    log.debug("接收的id:{}", id);    employeeService.deleteEmployee(id);    return "redirect:/employee/list";}
  • mapper

        delete from `employee`where id =#{id}

作者:扬眉剑出鞘
出处: https://www.cnblogs.com/eyewink/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。