springboot网上商城项目(一)

news2024/11/24 2:13:30

springboot网上商城项目(一)

    • (一)项目分析
        • 1.项目分析
        • 2.开发顺序
        • 3.前端资源测试
    • (二)用户注册
        • 1.创建数据库
        • 2.实体类编写
        • 3.注册(持久层)
        • 4.注册(业务层)
        • 5.注册(控制层)
        • 6.注册前端页面
      • 后记

🎁🎁静态资源及sql文件
链接:https://pan.baidu.com/s/1X-yjmQcPD3PqS21x0HplNA?pwd=23gr
提取码:23gr

(一)项目分析

1.项目分析

📝​📝项目功能:登录,注册,热销商品,用户管理(密码,个人信息,头像,收货地址),购物车(展示,增加,删除),订单模块
📝​📝开发顺序:注册,登录,用户管理,购物车,商品,订单模块

2.开发顺序

模块的开发顺序:
持久层开发:依据前端页面的设置规划相关的SQL语句,以及进行配置
业务层开发:核心功能控制,业务操作以及异常的处理
控制层开发:接收请求,处理响应
前端开发:JS,Query,AJAX这些技术来连接后台

3.前端资源测试

创建一个springboot项目导入前端静态资源 ,检测是否能够正常显示。如果这个过程访问失败,原因是idea对于JS代码的兼容性较差,编写了js代码但是有的时候不能正常去加载,解决办法有以下四种:

1.clear-install:依次点击MavenProject->store->Lifecycle->clean,等待清理项目完毕后点击同目录下的install重新部署

2.idea缓存清理:点击File下的Invalidate Caches/Restart…然后在弹出的窗口中选择Invalidate and Restart,此时就会自动清除缓存并重新启动idea

3.rebuild重新构建:点击工具栏的Build下的Rebuild Project

4.重启电脑

(二)用户注册

1.创建数据库

创建数据库t_user

CREATE TABLE t_user (
	uid INT AUTO_INCREMENT COMMENT '用户id',
	username VARCHAR(20) NOT NULL UNIQUE COMMENT '用户名',
	password CHAR(32) NOT NULL COMMENT '密码',
	salt CHAR(36) COMMENT '盐值',
	phone VARCHAR(20) COMMENT '电话号码',
	email VARCHAR(30) COMMENT '电子邮箱',
	gender INT COMMENT '性别:0-女,1-男',
	avatar VARCHAR(50) COMMENT '头像',
	is_delete INT COMMENT '是否删除:0-未删除,1-已删除',
	created_user VARCHAR(20) COMMENT '日志-创建人',
	created_time DATETIME COMMENT '日志-创建时间',
	modified_user VARCHAR(20) COMMENT '日志-最后修改执行人',
	modified_time DATETIME COMMENT '日志-最后修改时间',
	PRIMARY KEY (uid)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

2.实体类编写

创建用户表实体类(因为在用户表的设计中有4个公共字段,所以将这些字段字段提取出来放在一个实体基类baseEntity中)

//基类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class baseEntity implements Serializable {
    private String createdUser;
    private Date createdTime;
    private String modifiedUser;
    private Date modifiedTime;

实体类User继承baseEntity(实体类User因为要在网络中以流的形式传输,所以需要serialize序列化

//实体类
@Data
public class User extends baseEntity implements Serializable {
private Integer uid;
private String username;
private String password;
private String salt;
private String phone;
private String email;
private Integer gender;
private String avatar;
private Integer isDelete;

3.注册(持久层)

mapper接口

//用户模块持久层
//@Mapper
public interface UserMapper {
    //插入用户数据
     Integer insert(User user);
     //根据用户名查找用户数据
     User findByUsername(String username);
}

mapper的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">
<!--namespace用于指定当前的映射文件和哪个接口进行映射,需要指定接口的文件路径,路径需要是包的完整路径结构-->
<mapper namespace="com.cy.store.mapper.UserMapper">
    
    <resultMap id="UserEntityMap" type="com.cy.store.entity.User">
        <id column="uid" property="uid"></id>
        <result column="is_delete" property="isDelete"></result>
        <result column="created_user" property="createdUser"></result>
        <result column="created_time" property="createdTime"></result>
        <result column="modified_user" property="modifiedUser"></result>
        <result column="modified_time" property="modifiedTime"></result>
    </resultMap>
<insert id="insert" useGeneratedKeys="true" keyProperty="uid">

    insert into t_user(
        username,password,salt,phone,email,gender,avatar,is_delete,
        created_user,created_time,modified_user,modified_time) values (
                 #{username},#{password},#{salt},#{phone},#{email},#{gender},#{avatar},#{isDelete},#{createdUser},#{createdTime},#{modifiedUser},#{modifiedTime}
             )

</insert>
    <select id="findByUsername" resultMap="UserEntityMap">
select * from t_user where  username=#{username}
    </select>
</map

4.注册(业务层)

service层
接受前端从控制器流转过来的数据
结合真实的注册业务来完成功能业务逻辑的调转和流程

异常规划
比如,用户在进行注册时可能会产生用户名被占用的错误,这时需要抛出一个异常

1.异常不能用RuntimeException,太笼统了,开发者没办法第一时间定位到具体的错误类型上,我们可以定义具体的异常类型来继承这个异常。
2.正常的开发中异常又要分等级,可能是在业务层产生异常,可能是在控制层产生异常,所以可以创建一个业务层异常的基类,起名ServiceException异常,并使其继承RuntimeException异常。
3.后期开发业务层时具体的异常可以再继承业务层的异常ServiceException。

在service包下创建一个ex包再在下创建ServiceException类作为业务层异常的基类

public class ServiceException extends RuntimeException{
    public ServiceException() {
        super();
    }

    public ServiceException(String message) {
        super(message);
    }

    public ServiceException(String message, Throwable cause) {
        super(message, cause);
    }

    public ServiceException(Throwable cause) {
        super(cause);
    }

    protected ServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }
}

分别创建查询异常UsernameDuplicatedException 和插入异常的InsertException 类

public class UsernameDuplicatedException extends ServiceException{
    /**重写ServiceException的所有构造方法*/
}
//数据插入过程中产生异常
public class InsertException extends ServiceException{
    /**重写ServiceException的所有构造方法*/
}

创建IUserService接口(接口命名的默认规则:I+业务名字+层的名字)

//用户模块业务层接口
public interface IUserService {

    void reg(User user);
}

service实现serviceimpl类

@Service
public class UserServiceImpl implements IUserService {
    @Resource
    private UserMapper userMapper;

    @Override
    public void reg(User user) {
        String username=user.getUsername();
//调用findbyusername判断用户是否被注册
   User result= userMapper.findByUsername(username);
   if (result!=null){
       throw new UsernameDuplicatedException("用户已经存在");
   }
   //密码加密 md5加密算法
     //串(盐值)+password+串 ---md5进行加密 连续加载三次
        //盐值就是随机字符串
String oldPassword=user.getPassword();
       String salt= UUID.randomUUID().toString().toUpperCase();
       //记录盐值 登录进行密码比较
        user.setSalt(salt);
//将密码和盐值作为一个整体 加密
String md5password=getMd5Password(oldPassword,salt);
//重新加入
user.setPassword(md5password);
//补全数据
   user.setIsDelete(0);
        Date date=new Date();
   user.setCreatedTime(date);
   user.setModifiedTime(date);
   user.setCreatedUser(user.getUsername());
   user.setModifiedUser(user.getModifiedUser());
   Integer rows=userMapper.insert(user);
if (rows!=1){
    throw new InsertException("注册异常");
}
    }
//定义md5算法加密
    private String getMd5Password(String password,String salt){
       for (int i=0 ;i<3;i++){
           password=DigestUtils.md5DigestAsHex((salt+password+salt).getBytes()).toUpperCase();
       }
       return password;
    }
}

5.注册(控制层)

Controller层
请求路径:/users/reg
请求参数:User user
请求类型:POST
响应结果:JsonResult< void >

在controller包下创建BaseController 类作为控制层下类的基类,用来做统一的异常捕获:

public class BaseController {

    public static final int ok = 200;
    //请求处理方法,这个方法的返回值就是需要传递给前端数据
    //自动将异常对象传递给此方法的参数列表上
    //当前项目中产生了异常,被统一拦截到此方法中,这个方法此时充当的是请求处理方法,方法的返回值直接给前端
    @ExceptionHandler(ServiceException.class)//用于统一处理抛出异常
    public JsonResult<Void> handleException(Throwable e) {
        JsonResult<Void> result = new JsonResult<>(e);
        if (e instanceof UsernameDuplicatedException) {
            result.setState(400);
            result.setMessage("用户名存在");
        } else if (e instanceof InsertException){
            result.setState(500);
            result.setMessage("注册出现异常");
        }
        return result;

    }
}

创建UserController类,依赖于业务层的接口,继承BaseController并重构UserController下的reg方法。

@RestController
@RequestMapping("/users")
public class UserController extends BaseController{
    @Autowired
    private IUserService userService;
    @PostMapping("/reg")
    public JsonResult<Void> reg(@RequestBody User user){
       userService.reg(user);
        return new JsonResult<>(ok);
    }
}

6.注册前端页面

ajax函数:
这是jQuery封装的一个函数,称为$.ajax()函数,通过对象调用ajax()函数用来异步加载相关的请求.依靠的是JavaScript提供的一个对象:XHR(全称XmlHttpResponse)

ajax()函数的语法结构:
使用ajax()时需要传递一个方法体作为方法的参数来使用(一对大括号就是一个方法体)
ajax接受多个参数时,参数与参数之间使用",“分割
每一组参数之间使用”:"进行分割
参数的组成部分一个是参数的名称(不能随便定义),另一个是参数的值(必须用字符串来表示)
参数的声明顺序没有要求
语法结构:

$.ajax({
    url: "",
    type: "",
    data: "",
    dataType: "",
    success: function() {
        
    },
    error: function() {
        
    }
});

在这里插入图片描述

前端js代码

        <script>
            //1.监听注册按钮是否被点击,如果被点击可以执行一个方法(这里不能像ajax函数那样删去function()只留下{},这是官方规定的!)
            $("#btn-reg").click(function () {
                //let username = $("#username").val();
                //let pwd = $("#password").val();
                //上面这两行是动态获取表单中控件的数据,但是如果这样获取的话ajax函数中
                //就是data: "username="+username + "&password="+pwd,但太麻烦了,如
                // 果这个表单提交的是用户的兴趣爱好,那数据就很多了,一个表单20个数据都很正
                // 常,如果此时还用这种方式就太麻烦了,所以不建议用这种方式

                //2.发送ajax()的异步请求来完成用户的注册功能
                $.ajax({
                    url: "/users/reg",
                    type: "POST",

                    //serialize这个API会自动检测该表单有什么控件,每个控件检测后还会获取每个控
                    // 件的值,拿到这个值后并自动拼接成形如username=Tom&password=123的结构
                    data: $("#form-reg").serialize(),

                    dataType: "JSON",
                    success: function (json) { //1.js是弱数据类型,这个地方不用声明json的数据类型
                        //2.如果服务器成功响应就会将返回的数据传给形参,比如{state: 4000,message: "用户名
                        // 已经被占用",data: null}
                        if (json.state == 200) {
                            alert("注册成功")
                        } else {
                            alert("注册失败")
                        }
                    },
                    error: function (xhr) { //如果问题不在可控范围内,服务器就不会返回自己定
                        //义的json字符串:{state: 4000,message: "用户名已经被占用",data: null}
                        //而是返回一个XHR类型的对象,该对象也有一个状态码名字是status
                        alert("注册时产生未知的错误!"+xhr.status);
                    }
                });
            });
        </script>

浏览器上输入http://localhost:8080/web/register.html 测试注册功能是否可以注册。此时可能会出现点击注册提交表单时没有任何响应,原因是idea对于JS代码的兼容性较差,编写了js代码但是有的时候不能正常去加载,解决办法有四种,同前面的:项目环境搭建->项目测试->测试静态资源能否正常加载

后记

👉👉💕💕美好的一天,到此结束,下次继续努力!,写作不易,感谢大家的支持!! 🌹🌹🌹

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

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

相关文章

类ChatGPT的部署与微调(下):从ChatGLM-6b到ChatDoctor、可商用

前言 随着『GPT4多模态/Microsoft 365 Copilot/Github Copilot X/ChatGPT插件』的推出&#xff0c;绝大部分公司的技术 产品 服务&#xff0c;以及绝大部分人的工作都将被革新一遍 类似iPhone的诞生 大家面向iOS编程 有了App Store现在有了ChatGPT插件/GPT应用商店&#xff…

国产CMS61850那些事-服务端

前面两篇文章国产CMS61850那些事-总述_LinuxZQ的博客-CSDN博客&#xff0c;cms61850那些事-实现_LinuxZQ的博客-CSDN博客分别对国产61850做了一些简单介绍和相关实现。本文接着给大家提供一款服务端demo&#xff0c;可以用来进行抓包等相关学习。 与之前分享的mms 61850一样&am…

如此这般,好吗?

让我们回顾一下 Linux 社区最新的愿景——推动去中心化的应用来解决发行版的碎片化。继上周的文章&#xff1a;“Snap、Flatpak 这种通吃所有发行版的打包方式真的有用吗&#xff1f;” 之后&#xff0c;一系列新观点浮出水面&#xff0c;其中可能包含关于这样应用是否有用的重…

Vmware安装Ubuntu出现 unable to find a medium containing a live file system

一、前言 由于未知的原因&#xff0c;使用Vmware安装Ubuntu的时候&#xff0c;总是遇到奇怪的问题。&#xff08;忘记截图了…&#xff09; 大致是&#xff1a; unable to find a medium containing a live file system找了几个帖子&#xff0c;参考1、参考2&#xff0c;但都…

GPT模型成功的背后用到了哪些以数据为中心的人工智能(Data-centric AI)技术?

人工智能&#xff08;Artificial Intelligence, AI&#xff09;最近取得了巨大的进展&#xff0c;特别是大语言模型&#xff08;Large Language Models, LLMs&#xff09;&#xff0c;比如最近火爆全网的ChatGPT和GPT-4。GPT模型在各项自然语言处理任务上有着惊人的效果。至于具…

JAVA Future类详解及Thread线程是如何运行Future类的

一、Future基本介绍 Future(java.util.concurrent Interface Future<V>)表示异步计算的结果。Future接口提供了检查计算是否完成、检查计算是否被取消、等待计算完成并获取计算结果等方法。 在并发编程中&#xff0c;我们经常用到非阻塞的模型&#xff0c;但继承thread类…

基于 SpringBoot+Vue+Java 的留守儿童系统的研究与实现(附源码,教程)

文章目录 1.研究背景2. 技术栈3.系统分析4系统设计5系统的详细设计与实现5.1系统功能模块5.2管理员功能模块 1.研究背景 以往的留守儿童爱心的管理&#xff0c;一般都是纸质文件来管理留守儿童爱心信息&#xff0c;传统的管理方式已经无法满足现代人们的需求&#xff1b;使用留…

[激光原理与应用-69]:激光器-器件 - 三极管

第1章 什么是三级管 三极管&#xff0c;全称应为半导体三极管&#xff0c;也称双极型晶体管、晶体三极管&#xff0c;是一种控制电流的半导体器件。其作用是把微弱电流信号放大成幅度值较大的电流信号&#xff0c;也用作无触点开关。电流信号经过电阻后&#xff0c;就变成了电压…

ARM嵌入式编译器编译优化选项 -O

Arm嵌入式编译器可以执行一些优化来减少代码量并提高应用程序的性能。不同的优化级别有不同的优化目标&#xff0c;不仅如此&#xff0c;针对某个目标进行优化会对其他目标产生影响。比如想减小生成的代码量&#xff0c;势必会影响到该代码的性能。所以优化级别总是这些不同目标…

Python中 re.findAll()、re.sub()、set()的使用

1. re.findall() re.findall()&#xff1a;函数返回包含所有匹配项的列表。返回string中所有与pattern相匹配的全部字串&#xff0c;返回形式为list / 数组。 由函数原型代码可知&#xff0c;findall() 函数存在三个参数&#xff1a; 1. pattern&#xff1a;正则表达式中的 ‘模…

RK3568平台开发系列讲解(驱动基础篇)IO 模型的分类

🚀返回专栏总目录 文章目录 一、阻塞 IO二、非阻塞 IO三、IO 多路复用四、信号驱动五、异步 IO沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将针对IO模型进行分类。 假设有这样一个场景,从磁盘中循环读取 100M 的数据并处理,磁盘读取 100M 需要花费 20 秒的…

HR真的会嫌弃跳槽频繁的测试人员吗?

我们都知道&#xff1a;“跳槽≠涨薪”&#xff0c;但是对于测试人来说&#xff0c;跳槽绝哔能和升职加薪画上等号啊。 所以&#xff0c;有很多测试人在一家公司常常待不到1年&#xff0c;就另觅新东家&#xff0c;来借此达成升职加薪的目的。 有人提出质疑&#xff1a;为什么测…

【老王读SpringMVC-2】url 与 controller method 的映射关系注册

上文提到&#xff0c;如果我们自己要实现 spring mvc 框架的话&#xff0c;大致需要实现如下功能&#xff1a; 0、将 url 与 Controller method 的对应关系进行注册1、通过请求的 url 找到 Controller method (即 url 与 Controller method 的映射)2、将请求参数进行绑定&…

【python中的迭代器了解一下?】

基本说明 在 Python 中&#xff0c;迭代器是一种用于遍历可迭代对象&#xff08;如列表、元组、字符串等&#xff09;的方式。迭代器提供了一种简洁而有效的方法来遍历序列&#xff0c;而不需要创建临时变量或使用循环语句。 在 Python 中&#xff0c;迭代器是一个实现了 __i…

没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统)

环境: DELL7080台式机 Ubuntu20.04 两块硬盘 问题描述: 没有U盘电脑如何使用本地硬盘安装Ubuntu20.04(双系统) 解决方案: 一、下载镜像文件 1.上线自行下载安装镜像文件 二、分区 1.win10下磁盘管理压缩2个分区一个10G左右制作安装盘,一个几百G安装系统使用 10…

【Android入门到项目实战-- 7.1】—— 如何使用通知?

目录 一、创建通知的步骤 1、创建一个NotificationManager实例 2、使用一个Builder构造器来创建Notification对象 3、设置标题、文字、时间和图标等信息 4、显示通知 二、通知实例演示 三、实现通知的点击效果 1、PendingIntent 什么是PendingIntent&#xff1f; 如何使…

后台-husky提交代码规范使用

husky是一个git hook工具&#xff0c;可以帮助我们触发git提交的各个阶段&#xff1a;pre-commit、commit-msg、pre-push 1.如何使用husky呢&#xff1f; npx husky-init && npm installWindows安装不成功试试npx husky-init && npm install 2.git commit规范…

线索二叉树的前序遍历

线索二叉树原理 遍历二叉树的其实就是以一定规则将二叉树中的结点排列成一个线性序列&#xff0c;得到二叉树中结点的先序序列、中序序列或后序序列。这些线性序列中的每一个元素都有且仅有一个前驱结点和后继结点。 但是当我们希望得到二叉树中某一个结点的前驱或者后继结点时…

计算机组成原理---第 6 章总线系统

一、总线的概念和结构形态 总线的基本概念 ⑴概述 总线是构成计算机系统的互联机构&#xff0c;是多个系统功能部件之间进行数据传送的公共通路。 ⑵ 分类 总线的分类方式有很多&#xff1a;如被分为外部总线和内部总线、系统总线和非系统总线、片内总线和PCB板级总线、串行…

VS2022+opengl环境配置

glfw下载Download | GLFW glad下载https://glad.dav1d.de/ Freeglut下载 https://freeglut.sourceforge.net/index.php#download cmake下载 Download | CMake glfwFreeglut 用cmake配置Freeglut&#xff0c;生成vs工程项目&#xff0c;用vs2022编译项目&#xff0c;生成fr…