springboot网上商城项目(一)

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: (一)项目分析1.项目分析📝​📝项目功能:登录,注册,热销商品,用户管理(密码,个人信息,头像,收货地址),购物车(展示,增加,删除),订单模块📝​📝开发顺序:注册,登录,用户管理,购物车,商品,订单模块2.开发顺序模块的开发顺序:持久层开发:依据前端页面的设置规划相关的SQL语句,以及进行配置业务层开发:核心功能控制,业务操作以及异常的处理控制层开发:接收请求,处理响应前端开发:JS,Query,AJAX这些技术来连接后台

(一)项目分析

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类作为业务层异常的基类

publipublic 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() {
    }
});


347283be38e94ad5b4cb48217d69227e.png

前端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代码但是有的时候不能正常去加载,解决办法有四种,同前面的:项目环境搭建->项目测试->测试静态资源能否正常加载

后记

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

相关文章
|
6月前
|
Java Maven Android开发
微服务——SpringBoot使用归纳——Spring Boot开发环境搭建和项目启动
本文介绍了Spring Boot开发环境的搭建和项目启动流程。主要内容包括:jdk的配置(IDEA、STS/eclipse设置方法)、Spring Boot工程的构建方式(IDEA快速构建、官方构建工具start.spring.io使用)、maven配置(本地maven路径与阿里云镜像设置)以及编码配置(IDEA和eclipse中的编码设置)。通过这些步骤,帮助开发者顺利完成Spring Boot项目的初始化和运行准备。
532 0
微服务——SpringBoot使用归纳——Spring Boot开发环境搭建和项目启动
|
5月前
|
前端开发 安全 Java
Spring Boot 便利店销售系统项目分包设计解析
本文深入解析了基于Spring Boot的便利店销售系统分包设计,通过清晰的分层架构(表现层、业务逻辑层、数据访问层等)和模块化设计,提升了代码的可维护性、复用性和扩展性。具体分包结构包括`controller`、`service`、`repository`、`entity`、`dto`、`config`和`util`等模块,职责分明,便于团队协作与功能迭代。该设计为复杂企业级应用开发提供了实践参考。
203 0
|
2月前
|
Java 关系型数据库 MySQL
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
springboot项目集成dolphinscheduler调度器 实现datax数据同步任务
290 2
|
2月前
|
分布式计算 Java 大数据
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
springboot项目集成dolphinscheduler调度器 可拖拽spark任务管理
115 2
|
6月前
|
Java 测试技术 微服务
微服务——SpringBoot使用归纳——Spring Boot中的项目属性配置——少量配置信息的情形
本课主要讲解Spring Boot项目中的属性配置方法。在实际开发中,测试与生产环境的配置往往不同,因此不应将配置信息硬编码在代码中,而应使用配置文件管理,如`application.yml`。例如,在微服务架构下,可通过配置文件设置调用其他服务的地址(如订单服务端口8002),并利用`@Value`注解在代码中读取这些配置值。这种方式使项目更灵活,便于后续修改和维护。
86 0
|
6月前
|
Java 微服务 Spring
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——使用Logger在项目中打印日志
本文介绍了如何在项目中使用Logger打印日志。通过SLF4J和Logback,可设置不同日志级别(如DEBUG、INFO、WARN、ERROR)并支持占位符输出动态信息。示例代码展示了日志在控制器中的应用,说明了日志配置对问题排查的重要性。附课程源码下载链接供实践参考。
624 0
|
2月前
|
Java 测试技术 Spring
简单学Spring Boot | 博客项目的测试
本内容介绍了基于Spring Boot的博客项目测试实践,重点在于通过测试驱动开发(TDD)优化服务层代码,提升代码质量和功能可靠性。案例详细展示了如何为PostService类编写测试用例、运行测试并根据反馈优化功能代码,包括两次优化过程。通过TDD流程,确保每项功能经过严格验证,增强代码可维护性与系统稳定性。
121 0
|
2月前
|
存储 Java 数据库连接
简单学Spring Boot | 博客项目的三层架构重构
本案例通过采用三层架构(数据访问层、业务逻辑层、表现层)重构项目,解决了集中式开发导致的代码臃肿问题。各层职责清晰,结合依赖注入实现解耦,提升了系统的可维护性、可测试性和可扩展性,为后续接入真实数据库奠定基础。
210 0
|
3月前
|
网络协议 Java
在SpringBoot项目中使用Netty实现远程调用
本文介绍了使用Netty解决网络连接性能问题的方法,重点讲解了Netty的NIO特性及其在SpringBoot中的应用。Netty作为高效的NIO框架,支持非阻塞IO,能通过单线程管理多个客户端连接,简化TCP/UDP套接字服务器开发。文章详细展示了Netty在SpringBoot中实现远程调用的过程,包括服务端与客户端代码实现、依赖配置及测试验证。通过示例代码,如`NettyServer`、`NettyClientUtil`等,清晰说明了Netty的工作原理和实际应用,解决了半包等问题,并提供了完整的测试结果。
431 3
|
8月前
|
XML Java 应用服务中间件
SpringBoot项目打war包流程
本文介绍了将Spring Boot项目改造为WAR包并部署到外部Tomcat服务器的步骤。主要内容包括:1) 修改pom.xml中的打包方式为WAR;2) 排除Spring Boot内置的Tomcat依赖;3) 添加Servlet API依赖;4) 改造启动类以支持WAR部署;5) 打包和部署。通过这些步骤,可以轻松地将Spring Boot应用转换为适合外部Tomcat服务器的WAR包。
457 64
SpringBoot项目打war包流程