基于SSM框架的《超市订单管理系统》Web项目开发(第二天)完成登录模块和用户退出模块

news2025/1/12 20:44:58

《超市订单管理系统》(第二天) 基于SSM框架的Web项目开发

​ 昨天我们实现了登录功能,但是用的是模拟数据。今天我们要链接数据库整合Spirng+Mybatis,读取数据库中的真实数据,用来跟我们输入的userCode和userPassword进行对比,来判断用户名和密码是否正确。还需要进行一些其他的微调


今日目标:链接数据库完成以下模块设计

  • 完成登录模块(登录页面设计+登录功能)
  • 完成用户退出模块

项目的开发流程(一般来说)

项目的开发流程可以根据具体需求和项目规模有所不同,但通常包括以下主要步骤:

  1. 需求分析和规划
    • 理解项目的需求和目标。
    • 制定项目计划和时间表。
    • 确定项目的范围和功能。
  2. 数据库设计
    • 根据项目需求设计数据库结构,包括表和关系。
    • 创建数据库模式和表结构。
    • 确保数据库的正常运行和性能。
  3. 后端开发
    • 开发后端应用程序,包括业务逻辑和数据访问层。
    • 集成数据库,实现数据的增删改查操作。
    • 编写 API 和服务端逻辑。
  4. 前端开发
    • 开发前端界面和用户体验。
    • 使用 HTML、CSS、JavaScript 等前端技术。
    • 与后端进行通信,调用后端提供的 API。
  5. 集成和测试
    • 集成前后端组件,确保它们协同工作。
    • 进行单元测试和集成测试,检查功能和性能。
    • 解决和修复问题。
  6. 部署和上线
    • 部署应用程序到生产环境。
    • 配置服务器和数据库。
    • 监控应用程序性能,并处理生产问题。
  7. 维护和优化
    • 定期监控和维护应用程序,确保其稳定性。
    • 进行性能优化,提高应用程序效率。
    • 根据用户反馈和需求进行功能扩展和更新。
  8. 文档和培训
    • 编写项目文档,包括用户手册和开发文档。
    • 培训用户和开发团队,确保他们了解项目和工具。

​ 关于数据库的创建,通常在数据库设计阶段会创建数据库模式和表结构但在实际开发中,有时也可以在后期根据需求进行数据库的调整和扩展

这是因为,项目开发是一个迭代和持续改进的过程,需要我们不断地与团队成员者进行沟通和协作。

一般来说都是要提前设计好数据库表结构等,然后再去进行一个前后端的开发。在自己进行一个全新项目开发的时候呢,基本上是得按照上面的流程来。


一、开发前准备

①数据库准备:

运行Navicat for Mysql等数据库管理工具,导入我们项目资源中的数据库文件supermarket.sql

​ ps:Navicat 是一款强大的数据库管理工具,用于管理和维护多种数据库系统,包括 MySQL、MariaDB、SQLite、SQL Server、Oracle 和 PostgreSQL 等。它为数据库开发人员和管理员提供了丰富的功能和工具,使他们能够更轻松地管理和操作数据库。

创建出supermarket数据库。

②查看用户表中的所有字段,我们要确保我们的类中的属性和表中的字段名一致,一 一对应映射,这样涉及到前后端传值的时候就比较清晰,不会太迷糊,降低出错的风险。

在这里插入图片描述

二、开始完善登录功能

自动生成pojo类这个部分,我也是前面的文章有发布过的,可以访问查看一下

如何使用IDEA链接数据库并自动生成POJO类?_Stevedash的博客-CSDN博客如何实现

①确保正确的项目结构和资源文件的齐全

在这里插入图片描述

②使用idea自带链接数据库生成数据库表的pojo类与pojo包下,然后进行检查。

在这里插入图片描述

在这里插入图片描述

③dao层(dao包)下创建Mybatis的映射文件和接口,我们这里是对user表进行的操作,那么就是UserMapper接口和UserMapper.xml(也就是Mybatis映射文件)

看到这里可能会有疑惑

为什么dao层中的UserMapper接口要和UserMapper.xml的命名一样呢?

​ 其实我们前面的文章也有讲到的,在MyBatis这样的持久化框架中,UserMapper接口和UserMapper.xml的命名之间通常需要保持一致,这是为了确保MyBatis能够正确地将接口与XML配置文件关联起来并执行相应的SQL操作

UserMapper接口代码如下:

package com.steveDash.dao;

import com.steveDash.pojo.User;


public interface UserMapper {
    public User getUserByUserCode(String userCode);
}

UserMapper.xml代码如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.steveDash.dao.UserMapper">

    <!--根据账户名userCode查询user表,返回一个User类型对象记录-->
    <select id="getUserByUserCode" parameterType="String" resultType="User">
        select * from user where userCode=#{userCode}
    </select>
</mapper>

这里的返回类型本来是要写全类限名,但是我们在Mybatis-config配置文件中编写了别名,因此这里我们可以直接写User

在这里插入图片描述

在这里插入图片描述

按照我们前面讲的,这里应该还需要去mybatis-config里面注册好我们的mapper映射文件的地址吧?

但是呢,这里我们选择在spring-config中去写入配置Dao层,这样的话我们就不用一个一个的映射文件都要注册到配置文件中,这段代码它会自动扫描该包下的所有映射文件并且注册好

在这里插入图片描述


④根据分层思想,在Service层下,编写UserService接口。

UserService接口中添加查询用户的方法getUserByUserCode()

package com.steveDash.service;

import com.steveDash.pojo.User;

public interface UserService {
    public User getUserByUserCode(String userCode);
}

(使用给接口生成实现类的快捷键ALT+ENTER)编写业务实现类UserServiceImpl

package com.steveDash.service;

import com.steveDash.dao.UserMapper;
import com.steveDash.pojo.User;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userServiceImpl")
public class UserServiceImpl implements UserService {
    @Resource
    private UserMapper userMapper;

    public UserMapper getUserMapper() {
        return userMapper;
    }

    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Override
    public User getUserByUserCode(String userCode) {
        try{
        return userMapper.getUserByUserCode(userCode);
    }catch (RuntimeException e){
            e.printStackTrace();
            throw e;
        }
    }
}

代码说明:在这里我们将dao中的接口UserMapper的实例注入到UserServiceImpl,并调用它的getUserByUserCode方法查询数据

所以这里一定要添加getter,setter方法!!! 因为依赖注入Spring框架通过setter方法来注入userMapper的实例

因为我们是使用注解的方式,所以我们需要去Spring-config.xml中查看一下,是否开启了注解的代码

在这里插入图片描述


⑤打开controller包下的,UserController,进行登录方法doLogin()的修改

在这里插入图片描述

这种方式就是我们前几天学到的,依赖注入和IOC控制反转,由IOC容器创建对象,通过getBean的方式来获取实例对象。


这里请思考一下:下面这俩种写法效果都是一样的,那么为什么我们要选择第一种呢?

UserService userService=(UserServiceImpl)context.getBean("userServiceImpl");

UserServiceImpl userService=(UserServiceImpl)context.getBean("userServiceImpl");

答案如下:

两种方式的效果是一样的,但第一种方式更符合依赖注入和面向接口编程的原则,因为它将userService声明为接口类型,而不是具体的实现类型。这样做有助于降低耦合度,使代码更具灵活性。如果以后更改了UserService的实现类,第一种方式无需修改,而第二种方式则需要修改。因此,第一种方式通常更好一些。


⑥运行一下tomcat服务

测试1首先进行正确的账号密码输入测试:

在这里插入图片描述

可以看到正常运行,并且没有错误。

还需要进行其他情况的测试2,比如用户名不存在的情况admin1,预期输出结果:用户名错误

在这里插入图片描述

与预期结果一致。

那么在进行登录测试3:账号正确,密码错误的情况。预期结果:用户名或者密码错误

在这里插入图片描述

与预期结果一致。


⑦代码反思优化,采用依赖注入的方式

上面的代码还有优化的空间,因为

在这里插入图片描述

蓝色标注的这一段,我们只是为了获取userServiceImpl的Bean,所以我们可以使用依赖注入的方式,代码如下:

package com.steveDash.controller;

import com.steveDash.pojo.User;
import com.steveDash.service.UserService;
import com.steveDash.service.UserServiceImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;

@Controller
public class UserController {
    @Resource
    private UserService userService;

    @RequestMapping(value="/login")
    public String showLoginPage(){
        System.out.println("进入登录页面");
        return "login";
    }

    @RequestMapping(value="/dologin")
    public String doLogin(@RequestParam("userCode") String userCode, @RequestParam("userPassword") String userPassword, Model model, HttpSession session){
        //读取用户和密码
        System.out.println("帐号和密码是"+userCode+"-"+userPassword);
        User user=userService.getUserByUserCode(userCode);
        if(user!=null){
        if(userPassword.equals(user.getUserPassword())){
           session.setAttribute("userCode",userCode);//添加session值
            return "welcome"; //密码正确就去welcome.jsp
        }else{
            //登录失败就回到login.jsp
            model.addAttribute("error", "用户名或密码不正确");
            return "login";
        }
    }else{
        //登录失败就返回login.jsp
            model.addAttribute("error", "用户名不正确");
            return "login";
        }
    }

}

⑧重新运行服务,看看需求是否满足,登录功能是否正常?

在这里插入图片描述

在这里插入图片描述


三、完成退出模块

​ 退出登录模块的设计,其实就是清除httpSession中的Session,然后进行判断若是Session中没有用户,那就判断回到登录页面,若有就跳转到主功能页面,这样子就可以完成一个退出的功能。

所以在完成退出模块设计前,要对我们刚刚实现的登录功能进行一个优化

①我们Session中只存了用户的账号名:userCode,可是我们其他页面或许需要user用户的其他参数,因此我们修改Session中存储的值,修改为存储user用户

在UserController.java找到doLogin并且进行修改

@RequestMapping(value="/dologin")
public String doLogin(@RequestParam("userCode") String userCode, @RequestParam("userPassword") String userPassword, Model model, HttpSession session){
    //读取用户和密码
    System.out.println("帐号和密码是"+userCode+"-"+userPassword);
    User user=userService.getUserByUserCode(userCode);
    if(user!=null){
    if(userPassword.equals(user.getUserPassword())){
       session.setAttribute("user",user);//添加session值,修改成存入user对象
        return "redirect:/main"; //密码正确就去welcome.jsp(main是welcome页面的映射)
    }else{
        //登录失败就回到login.jsp
        model.addAttribute("error", "用户名或密码不正确");
        return "login";
    }
}else{
    //登录失败就返回login.jsp
        model.addAttribute("error", "用户名不正确");
        return "login";
    }
}

所以我们还需要添加一个去到welcome页面的映射,因此还是在UserController中进行如下操作

新增/main映射到welcome.jsp页面

@RequestMapping(value="/main")
public String welcome(HttpSession session)  {
    if(session.getAttribute("user") == null){ //如果用户没有登录就直接来到main.html就回到login
        return "redirect:/syserror";
    }
    else
        return "welcome";
}

 @RequestMapping("/syserror")//出错页面
    public String sysError(){
        return "syserror";
    }

​ 这里为什么不是直接使用welcome作为页面的映射呢?这是基于一个网络安全的考虑,因为直接让映射名和文件名一致的话,很容易就被黑客找到关键资源文件,进行渗透攻击修改后台数据,因此我们都是用关键词代表这个映射的操作。

​ 我们这里还加入了一个判断,若是没有登陆就想直接访问main界面,就会自动重定向到syserror.jsp报错页面

<%--
  Created by IntelliJ IDEA.
  User: Administrator
  Date: 2023/9/17
  Time: 11:39
  To change this template use File | Settings | File Templates.
--%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Insert title here</title>
</head>
<body>
<h1>请登录后再访问该页面!</h1>
<a href="${pageContext.request.contextPath }/login">返回</a>
</body>
</html>

在这里插入图片描述

**在这里插入图片描述
**

上面这样子就完善了登录页面的操作,并且设置了主页welcome的main映射,然后还编写了未登录就访问主页的错误提示。


②编写退出操作

代码如下:

@RequestMapping(value = "/logout")
public String logout(HttpSession session){
    session.removeAttribute("user");//清除掉Session 中的user值
    return "redirect:/login";//返回login.jsp
}

使用removeAttribute()方法清除掉session中存储的user对象,然后重定向到登录界面即可完成退出操作。

重新运行服务看看效果

在这里插入图片描述

在这里插入图片描述

可以看到了退回了登录界面,退出功能也完成了。


总结

​ 今天是综合项目超市订单管理系统开发的第二天,我们完善了登录的功能模块和退出的功能模块。项目现在已经整合了SpringMVC和Spring、以及Mybatis,算是SSM的综合项目了,接下里的就是把之前学习过的知识,应用在这个项目中还讲解了一下项目的开发流程,希望通过今天的学习,希望各位读者可以对整体的项目开发流程有个大致的了解,为框架开发打下坚实基础。

​ 想要跟着学习的可以去我的资源里面找对应的文件下载,我的md文件也会发上去,项目文件会上传可以自己跟着学习一下。(ps:前俩天有事,所以今天补上)

作者:Stevedash

发表于:2023年9月17日 13点23分

注:本文内容基于个人学习理解,如有错误或疏漏,欢迎指正。感谢阅读!如果觉得有帮助,请点赞和分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016925.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iText实战--根据绝对位置添加内容

3.1 direct content 概念简介 pdf内容的4个层级 层级1&#xff1a;在text和graphics底下&#xff0c;PdfWriter.getDirectContentUnder() 层级2&#xff1a;graphics层&#xff0c;Chunk, Images背景&#xff0c;PdfPCell的边界等 层级3&#xff1a;text层&#xff0c;Chun…

2023年商会研究报告

第一章 行业发展概况 1.1 定义和功能 商会&#xff0c;通常被称为商业协会或商业会所&#xff0c;是由具有相似的行业、商业、贸易、专业或地理背景的企业和商家所组成的组织。这些组织的核心目标是促进其会员之间的交流、合作和互助&#xff0c;进而推动相关行业或商业领域的…

Docker Swarm集群部署

Docker Swarm集群部署 任务平台 3台虚拟机&#xff0c;一台作为manager 节点&#xff0c;另两台作为work节点。 文章目录 Docker Swarm集群部署安装docker配置防火墙开放端口在 manager 节点创建 Swarm 集群创建用于swarm服务的自定义的overlay网络测试跨主机容器通信 安装do…

Python教程:@符号的用法

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程&#xff0c;尽在下方&#xff0c;赶紧点击了解吧~ python源码、视频教程、插件安装教程、资料我都准备好了&#xff0c;直接在文末名片自取就可 符号在 Pyth…

LLC谐振变换器软启动过程分析与问题处理

启动步骤 1.使用Burst模式升压至200V—稳定的充电5S钟&#xff0c;保证所有电容完全充满。 Burst模式过程&#xff1a;1.开启一次脉冲发送–>判断母线电压大小&#xff0c;确定下次启动脉冲的时间档位–>连续启停控制–>不断给电容充电–>进入200V稳定充电状态–…

Acwing.240 食物链(并查集)

题目 动物王国中有三类动物A,B,C&#xff0c;这三类动物的食物链构成了有趣的环形。A吃B&#xff0c;B吃C&#xff0c;C吃A。 现有N个动物&#xff0c;以1–N编号。 每个动物都是A,B,C中的一种&#xff0c;但是我们并不知道它到底是哪一种。有人用两种说法对这N个动物所构 成…

深度融入垂直行业是物联网未来发展必由之路

三年疫情&#xff0c;打断了很多企业的发展进程。但是疫情已过似乎整个业界生态有了一个很大变化。有一个朋友前一段时间参加深圳电子展后有一个感悟&#xff0c;说的很好&#xff1a;“疫情后有很大变化&#xff0c;疫情后&#xff0c;整个环境状态和疫情前有很大不同。无论企…

opencv练习-案例

import cv2 as cv import numpy as np from matplotlib import pyplot as plt %matplotlib inline图像分割是计算机将图像分割成多个区域的过程 使用阈值分割图像&#xff0c;产生两个区域 打开图像文件 img cv.imread(snake.png,cv.IMREAD_COLOR) gray cv.cvtColor(img,c…

OmniShade - Mobile Optimized Shader

OmniShade Pro是一款专为移动设备设计的高性能着色器。它包含多种技术,使其几乎可以实现从现实到卡通到动漫的任何外观,但由于自适应系统仅计算任何功能集所需的内容,它的速度也非常快。 它旨在弥合Unity的标准着色器和移动着色器之间的差距,但由于其高级别的风格化、组合…

系统架构设计师(第二版)学习笔记----信息安全基础知识

【原文链接】系统架构设计师&#xff08;第二版&#xff09;学习笔记----信息系统基础 文章目录 一、信息安全的概念1.1 信息安全的基本要素1.2 信息安全的内容1.3 设备安全的内容1.4 数据安全的内容1.5 内容安全的含义1.6 行为安全的含义 二、 信息存储安全2.1 信息存储安全的…

怎么实现一个登录时需要输入验证码的功能

今天给项目换了一个登录页面&#xff0c;而这个登录页面设计了验证码&#xff0c;于是想着把这个验证码功能实现一下吧。 这篇文章就如何实现登录时的验证码的验证功能结合代码进行详细地介绍&#xff0c;以及介绍功能实现的思路。 目录 页面效果 实现思路 生成验证码的控制…

水仙花数(熟悉Python后再写)

CSDN问答社区的一个提问&#xff0c;勾起我当时写代码的烦困。 (本笔记适合熟悉一门编程语言的 coder 翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xff1a;大咖免费“圣经”教程《 python 完全自学教程》&#xff0c;不仅仅是…

Vulnhub实战-DC9

前言 本次的实验靶场是Vulnhub上面的DC-9&#xff0c;其中的渗透测试过程比较多&#xff0c;最终的目的是要找到其中的flag。 一、信息收集 对目标网络进行扫描 arp-scan -l 对目标进行端口扫描 nmap -sC -sV -oA dc-9 192.168.1.131 扫描出目标开放了22和80两个端口&a…

【C语言基础】操作符、转义字符以及运算法大全,文中附有详细表格

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

【学习笔记】Java 一对一培训(第一部分)开发工具介绍和安装

【学习笔记】Java 一对一培训&#xff08;第一部分&#xff09;开发工具介绍和安装 关键词&#xff1a;Java、Spring Boot、Idea、数据库、一对一、培训、教学本文主要内容含开发工具总体介绍、JDK安装、IntelliJ IDEA 安装、MySQL安装、Navicat安装、Redis和RDM安装等计划30分…

Java:升序数组插入一个元素,结果依旧是升序

有一个升序的数组&#xff0c;要求插入一个元素&#xff0c;该数组顺序依然是升序。该数组{10&#xff0c;12&#xff0c;40&#xff0c;70} package input.java; import java.util.Scanner; public class lizi2 {public static void main(String[] args){int temp 0;int arr…

vue项目打包时如何将静态文件打包到一个单独的文件夹

在Vue项目中&#xff0c;你可以使用Webpack的配置来实现将静态文件打包到一个单独的文件夹。下面是一种常见的方法&#xff1a; 在Vue项目的根目录下&#xff0c;创建一个名为static的文件夹&#xff08;如果还没有&#xff09;。这个文件夹将用于存放静态文件。在vue.config.j…

代码随想录 -- day53 -- 1143.最长公共子序列 、1035.不相交的线、53. 最大子序和

1143.最长公共子序列 dp[i][j]&#xff1a;长度为[0, i - 1]的字符串text1与长度为[0, j - 1]的字符串text2的最长公共子序列为dp[i][j] 主要就是两大情况&#xff1a; text1[i - 1] 与 text2[j - 1]相同&#xff0c;text1[i - 1] 与 text2[j - 1]不相同 如果text1[i - 1] 与…

mybatis学习记录(二)-----CRUD--增删改查

目录 使用MyBatis完成CRUDz--增删改查 3.1 insert&#xff08;Create&#xff09; 3.2 delete&#xff08;Delete&#xff09; 3.3 update&#xff08;Update&#xff09; 3.4 select&#xff08;Retrieve&#xff09; 查询一条数据 查询多条数据 使用MyBatis完成CRUDz-…

【基础篇】ClickHouse 表引擎详解

文章目录 0. 引言1. 什么是表引擎2. 不同表引擎使用场景1. MergeTree:2. Log:3. Memory:4. Distributed:5. Kafka:6. MaterializedView:7. File和URL: 3. MergeTree 家族3.1. MergeTree:3.2. ReplacingMergeTree:3.3. SummingMergeTree:3.4. AggregatingMergeTree:3.5. Collaps…