详解基于SpringBoot如何构建电商秒杀项目

小编这次要给大家分享的是详解基于SpringBoot如何构建电商秒杀项目,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获。

创新互联长期为上千余家客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为双湖企业提供专业的成都网站建设、成都做网站双湖网站改版等技术服务。拥有十载丰富建站经验和众多成功案例,为您定制开发。

一、项目功能概述

电商秒杀需要完成的3个功能:

1.展示一个商品列表页面,我们可以从中看到可秒杀的商品列表

2.点击进入商品详情页,获取该商品的详细信息

3.秒杀时间开始后,点击进入下单确认页面,并支付成功

二、基于SpringBoot进行项目环境搭建

步骤1:创建一个maven工程,使用quickStart骨架。

步骤2:在pom.xml导入SpringBoot相关依赖。

 <?xml version="1.0" encoding="UTF-8"?>
 
 
  4.0.0 
  org.example
  Spike
  1.0-SNAPSHOT
 
  Spike
  
  http://www.example.com 
 
  org.springframework.boot
  spring-boot-starter-parent
  2.0.5.RELEASE
  
  
   UTF-8
   1.8   1.8
   
  
   
    org.springframework.boot
    spring-boot-starter-web
   
   
    junit
    junit
    4.11
    test
   
   
  
   
    
     
     
     maven-clean-plugin
      3.1.0
     
     
     
      maven-resources-plugin
      3.0.2
     
     
      maven-compiler-plugin
      3.8.0
     
     
      maven-surefire-plugin
      2.22.1
     
     
      maven-jar-plugin
      3.0.2
     
     
      maven-install-plugin
      2.5.2
    
     
      maven-deploy-plugin
      2.8.2
     
     
     
      maven-site-plugin
      3.7.1
     
     
      maven-project-info-reports-plugin
      3.0.0
     
    
   
  
 

步骤3:在main/java/app中,我们对SpringBoot和SpringMVC进行简单的配置工作。掌握这几个注解的作用。

package org.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

//SpringBoot会帮我们启动tomcat,并加载默认配置
@EnableAutoConfiguration
//SpringMVC相关配置
@RestController
public class App {
  @RequestMapping("/")
  public String home(){
    //网页中输出
    return "Hello World!";
  }
  public static void main( String[] args ){
    //控制台输出
    System.out.println( "Hello World!" );
    SpringApplication.run(App.class,args);
  }
}

运行结果:

用浏览器打开http://localhost:8080/,我们可以看到页面上输出:Hello World!

同时,控制台也输出了Hello World!,以及一些Spring相关的信息。

SpringBoot小技巧:可以在resource目录下创建一个application.propeties配置文件,在其中写:server.port = 端口号来设置端口号。

步骤4:接入mybatis,首先在pom.xml添加需要的依赖(MySQL,druid连接池,mybatis)

写一个plugin标签,引入对应的mybatis自动生成文件的插件 {

添加对应的依赖:mybatis generator的core(第一次使用要单独在前面导入依赖,不可直接放在plugin中),mysql数据库的解析

写一个excution标签:设置允许移动生成的文件,允许自动覆盖文件(实际工作中不可以)

写一个configuration标签:指定mybatis generator 配置文件的路径 }

1 <?xml version="1.0" encoding="UTF-8"?>
 2 
 3 
 5  4.0.0
 6 
 7  org.example
 8  Spike
 9  1.0-SNAPSHOT
 10 
 11  Spike
 12  
 13  http://www.example.com
 14 
 15 
 16  org.springframework.boot
 17  spring-boot-starter-parent
 18  2.0.5.RELEASE
 19 
 20 
 21  
 22   UTF-8
 23   1.8
 24   1.8
 25  
 26 
 27  
 28   
 29    org.springframework.boot
 30    spring-boot-starter-web
 31   
 32   
 33    mysql
 34    mysql-connector-java
 35    5.1.6
 36   
 37   
 38    com.alibaba
 39    druid
 40    1.1.3
 41   
 42   
 43    org.mybatis.spring.boot
 44    mybatis-spring-boot-starter
 45    1.3.1
 46   
 47   
 48    junit
 49    junit
 50    4.11
 51    test
 52   
 53   
 54    org.mybatis.generator
 55    mybatis-generator-core
 56    1.3.5
 57   
 58  
 59 
 60  
 61   
 62    
 63     
 64     
 65      maven-clean-plugin
 66      3.1.0
 67     
 68     
 69     
 70      maven-resources-plugin
 71      3.0.2
 72     
 73     
 74      maven-compiler-plugin
 75      3.8.0
 76     
 77     
 78      maven-surefire-plugin
 79      2.22.1
 80     
 81     
 82      maven-jar-plugin
 83      3.0.2
 84     
 85     
 86      maven-install-plugin
 87      2.5.2
 88     
 89     
 90      maven-deploy-plugin
 91      2.8.2
 92     
 93 
 94     
 95     
 96      maven-site-plugin
 97      3.7.1
 98     
 99     
100      maven-project-info-reports-plugin
101      3.0.0
102     
103 
104     
105      org.mybatis.generator
106      mybatis-generator-maven-plugin
107      1.3.5
108      
109       
110        org.mybatis.generator
111        mybatis-generator-core
112        1.3.5
113       
114       
115        mysql
116        mysql-connector-java
117        5.1.6
118       
119      
120      
121       
122        mybatis generator
123        package
124        
125         generate
126        
127       
128      
129      
130       
131       true
132       
133       true
134       
135       
136        src/main/resource/mybatis-generator.xml
137       
138      
139     
140 
141    
142   
143  
144 

步骤5:创建mysql底层的数据库与相关表格

1.创建数据库spike

2.创建一个user_info表格

详解基于SpringBoot如何构建电商秒杀项目

3.创建一个user_password表格,并设置user_id为外键关联user_info的id

详解基于SpringBoot如何构建电商秒杀项目

步骤6:在步骤4中,我们最后指定了mybatis generator 配置文件的路径,于是我们在指定路径(resource目录下)创建一个mybatis generator.xml,并进行如下配置:

<?xml version="1.0" encoding="UTF-8"?>


  
    
    
    
    
    
      
      
    
    
    
      
    
    
    
      
    
    
    

步骤7:根据步骤6中指定的位置,我们在org.example目录下新建一个dataobject的包,一个dao包。并测试是否能够成功生成相应的文件:

run——edit configurations——+maven——command line:mybatis-generator:generate——apply

然后我们运行这个新建的命令,可以看到resources/mapping下多了两个文件:

详解基于SpringBoot如何构建电商秒杀项目

dataobject包与dao包下生成了如下文件:

详解基于SpringBoot如何构建电商秒杀项目

手动删除两个Example文件。

步骤8:为了接入mybatis对应mysql的数据源,我们继续编写application.properties文件

 server.port = 8090
 mybatis.mapperLocations = classpath:mapping/*.xml
 
 spring.datasource.name = Spike
 spring.datasource.url = jdbc:mysql://127.0.0.1:3306/Spike
 spring.datasource.username = root
 spring.datasource.password = 0322
 
 #使用druid数据源
 spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
 spring.datasource.driverClassName = com.mysql.jdbc.Driver

步骤9:回到app.java

将@EnableAutoConfiguration注解改为@SpringBootApplication(scanBasePackages = "org.example"),作用是将app交给spring托管,并且指定为主启动类。

添加注解@MapperScan("org.example.dao"),把dao存放的地方设置在对应注解下面。

最后,写一个方法来测试我们的搭建工作是否完成,(事先在表格中添加一条数据)

 package org.example; 
 import org.example.dao.UserDoMapper;
 import org.example.dataobject.UserDo;
 import org.mybatis.spring.annotation.MapperScan;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
 //SpringBoot会帮我们启动tomcat,并加载默认配置
 @SpringBootApplication(scanBasePackages = {"org.example"})
 
 //SpringMVC相关配置
 @RestController
 @MapperScan("org.example.dao")
 public class App {
   @Autowired
   private UserDoMapper userDoMapper;
 
   @RequestMapping("/")
   public String home(){
     UserDo userDo = userDoMapper.selectByPrimaryKey(1);
     if(userDo == null){
      return "用户对象不存在";
     }else{
       return userDo.getName();
     } 
   }
   public static void main( String[] args ){
     //控制台输出
     System.out.println( "Hello World!" );
     SpringApplication.run(App.class,args);
   }
 }
app.java

打开http://localhost:8090/,我们可以看到页面上显示了我们添加的数据中name字段的内容。

三、用户模块开发

1.使用SpingMVC模式开发用户信息

步骤1:补全框架结构:

详解基于SpringBoot如何构建电商秒杀项目

步骤2:service层的编写:

UserService接口:

package org.example.service;
import org.example.service.model.UserModel;
public interface UserService {
  UserModel getUserById(Integer id);
}

UserService实现类:

@Service
public class UserServiceImpl implements UserService {
  @Autowired
  private UserDoMapper userDoMapper;

  @Autowired
  private UserPasswordDOMapper userPasswordDOMapper;

  @Override
  public UserModel getUserById(Integer id) {
    UserDo userDo = userDoMapper.selectByPrimaryKey(id);
    if(userDo == null){
      return null;
    }
    //通过用户id获取对应的用户加密密码信息
    UserPasswordDO userPasswordDO = userPasswordDOMapper.selectByUserId(userDo.getId());
    return convertFromDataObject(userDo,userPasswordDO);
  }

  public UserModel convertFromDataObject(UserDo userDo, UserPasswordDO userPasswordDO) {
    if(userDo == null){
      return null;
    }
    UserModel userModel = new UserModel();
    BeanUtils.copyProperties(userDo,userModel);
    if(userPasswordDO != null){
      userModel.setEncriptPassword(userPasswordDO.getEncriptPassword());
    }
    return userModel;
  }
}

UserModel类:存放数据库的所有对应字段与getters&setters,用于service层与数据库数据的解耦,使service层无法直接接触数据库

1 package org.example.service.model;
 2 
 3 public class UserModel {
 4   private Integer id;
 5   private String name;
 6   private Byte gender;
 7   private Integer age;
 8   private String telephone;
 9   private String registerMode;
10   private String thirdPartyId;
11   private String encriptPassword;
12 
13   public Integer getId() {
14     return id;
15   }
16 
17   public void setId(Integer id) {
18     this.id = id;
19   }
20 
21   public String getName() {
22     return name;
23   }
24 
25   public void setName(String name) {
26     this.name = name;
27   }
28 
29   public Byte getGender() {
30     return gender;
31   }
32 
33   public void setGender(Byte gender) {
34     this.gender = gender;
35   }
36 
37   public Integer getAge() {
38     return age;
39   }
40 
41   public void setAge(Integer age) {
42     this.age = age;
43   }
44 
45   public String getTelephone() {
46     return telephone;
47   }
48 
49   public void setTelephone(String telephone) {
50     this.telephone = telephone;
51   }
52 
53   public String getRegisterMode() {
54     return registerMode;
55   }
56 
57   public void setRegisterMode(String registerMode) {
58     this.registerMode = registerMode;
59   }
60 
61   public String getThirdPartyId() {
62     return thirdPartyId;
63   }
64 
65   public void setThirdPartyId(String thirdPartyId) {
66     this.thirdPartyId = thirdPartyId;
67   }
68 
69   public String getEncriptPassword() {
70     return encriptPassword;
71   }
72 
73   public void setEncriptPassword(String encriptPassword) {
74     this.encriptPassword = encriptPassword;
75   }
76 }

步骤3:修改UserPasswordDOMapper.xml,添加一个selectByUserId操作的配置

同步修改UserPasswordDOMapper.java,添加一行代码:

UserPasswordDO selectByUserId(Integer userId);

步骤4:编写Controller包中的UserController.java

@Controller("user")
@RequestMapping("/user")
public class UserController {
  @Autowired
  private UserService userService;
  @RequestMapping("/get")
  @ResponseBody
  public UserModel getUser(@RequestParam(name="id") Integer id) {
    //调用service服务获取对应id的用户对象并返回给前端
    UserModel userModel = userService.getUserById(id);
    return userModel;
  }
}

运行后,访问http://localhost:8090/user/get?id=1(需要事先添加好一条完整的数据),可以看到页面上输出了这条数据的完整信息。

步骤5:发现问题:在UserController中,我们把userModel模型直接返回给前端,导致密码直接输出在页面中,这是非常不专业的。

因此,我们在controller层(包)中需要新建一个模型对象。在controller层中新建一个viewobject包,并在其中写一个viewobject类,里面只写需要展示在前端的字段与getters&setters。

1 package org.example.controller.viewobject;
 2 
 3 public class UserVO {
 4   //只写前端用户所需要的信息
 5   private Integer id;
 6   private String name;
 7   private Byte gender;
 8   private Integer age;
 9   private String telephone;
10 
11   public Integer getId() {
12     return id;
13   }
14 
15   public void setId(Integer id) {
16     this.id = id;
17   }
18 
19   public String getName() {
20     return name;
21   }
22 
23   public void setName(String name) {
24     this.name = name;
25   }
26 
27   public Byte getGender() {
28     return gender;
29   }
30 
31   public void setGender(Byte gender) {
32     this.gender = gender;
33   }
34 
35   public Integer getAge() {
36     return age;
37   }
38 
39   public void setAge(Integer age) {
40     this.age = age;
41   }
42 
43   public String getTelephone() {
44     return telephone;
45   }
46 
47   public void setTelephone(String telephone) {
48     this.telephone = telephone;
49   }
50 }

同时,我们修改UserController类,将UserModel转化为viewobject后,再返回给前端。

@Controller("user")
@RequestMapping("/user")
public class UserController {
  @Autowired
  private UserService userService;
  @RequestMapping("/get")
  @ResponseBody
  public UserVO getUser(@RequestParam(name="id") Integer id) {
    //调用service服务获取对应id的用户对象并返回给前端
    UserModel userModel = userService.getUserById(id);
    //将核心领域模型对象转化为可供UI使用的viewobject
    return convertFromModel(userModel);
  }
  private UserVO convertFromModel(UserModel userModel){
    if(userModel == null){
      return null;
    }
    UserVO userVO = new UserVO();
    BeanUtils.copyProperties(userModel,userVO);
    return userVO;
  }
}

这一步中,我们做了一个完整的从数据库中读取数据,展示在前端页面上的操作。

controller层——>service层——>dao层

dataobject层负责数据存储到service的传输,并且在用户的service的服务中组装了对应的核心领域模型。

controller层做了到用户viewobject之间的传递,保证密码等信息不会输出到前端。

2.定义通用的返回对象

步骤1:自主管理前端页面的返回——返回正确信息

org.example包下创建一个response包,在其中创建一个CommonReturnType.java文件。

在该文件中,设置两个属性:status,data,并生成对应的getters&setters。然后写两个构造方法,包含了两个属性的设置。

 package org.example.response;
 
 public class CommonReturnType {
   //表名对应请求的返回处理结果,success/fail
   private String status;
   //若status返回success,则data内返回前端需要的json数据
   //若status返回success,则data内使用通用的错误码格式
   private Object data;
 
   //定义一个通用的创建方法
   public static CommonReturnType create(Object result){
     return CommonReturnType.create(result,"success");
   }
 
   public static CommonReturnType create(Object result,String status){
     CommonReturnType type = new CommonReturnType();
     type.setStatus(status);
     type.setData(result);
     return type;
   } 
   public String getStatus() {
     return status;
   }
 
   public void setStatus(String status) {
     this.status = status;
   } 
   public Object getData() {
     return data;
   } 
   public void setData(Object data) {
     this.data = data;
   }
 }

修改我们的UserController.java,将返回值改为CommonReturnType,由CommonReturnType调用create方法来引用UserVO中的信息。以下代码为需要修改的部分:

public CommonReturnType getUser(@RequestParam(name="id") Integer id) {
    //调用service服务获取对应id的用户对象并返回给前端
    UserModel userModel = userService.getUserById(id);
    //将核心领域模型对象转化为可供UI使用的viewobject
    UserVO userVO = convertFromModel(userModel);
    //返回通用对象
    return CommonReturnType.create(userVO);
  }

运行后,我们仍然访问http://localhost:8090/user/get?id=1,可以看到页面上输出了:

详解基于SpringBoot如何构建电商秒杀项目

步骤2:自主管理前端页面的返回——返回错误信息

org.example包下创建一个error包,在其中创建一个CommonError接口,写3个方法:获取错误码,获取错误信息,设置错误信息

 public interface CommonError {
   public int getErrCode();
   public String getErrMsg();
   public CommonError setErrMsg(String errMsg);
 }

error包下写一个枚举类型的EmBusinessError,实现CommonError接口。

package org.example.error;

public enum EmBusinessError implements CommonError{
  //通用错误类型10001
  PARAMETER_VALIDATION_ERROR(10001,"参数不合法"),
  //未知错误10002
  UNKNOWN_ERROR(10002,"未知错误"),

  //20000开头相关为用户信息相关错误定义
  USER_NOT_EXIST(20001,"用户不存在"),
  ;

  private EmBusinessError(int errCode,String errMsg){
    this.errCode = errCode;
    this.errMsg = errMsg;
  }

  private int errCode;
  private String errMsg;

  @Override
  public int getErrCode() {
    return this.errCode;
  }

  @Override
  public String getErrMsg() {
    return this.errMsg;
  }

  @Override
  public CommonError setErrMsg(String errMsg) {
    this.errMsg = errMsg;
    return this;
  }
}

error包下写一个BusinessException,实现CommonError接口,并继承Exception类。

public class BusinessException extends Exception implements CommonError{
  private CommonError commonError;

  //直接接收EmBusinessError的传参用于构造业务异常
  public BusinessException(CommonError commonError) {
    super();
    this.commonError = commonError;
  }

  public BusinessException(CommonError commonError,String errMsg) {
    super();
    this.commonError = commonError;
    this.commonError.setErrMsg(errMsg);
  }

  @Override
  public int getErrCode() {
    return this.commonError.getErrCode();
  }

  @Override
  public String getErrMsg() {
    return this.commonError.getErrMsg();
  }

  @Override
  public CommonError setErrMsg(String errMsg) {
    this.commonError.setErrMsg(errMsg);
    return this;
  }
}

UserController中添加如下代码:

   //若获取的对应用户信息不存在
     if(userModel==null){
       throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
     }

步骤3:异常处理

在controller目录下单独写一个BaseController类,定义exceptionhandler解决未被controller层吸收的exception。

import java.util.Map;

public class BaseController {
  //定义exceptionhandler解决未被controller层吸收的exception
  @ExceptionHandler(Exception.class)
  @ResponseStatus(HttpStatus.OK)
  @ResponseBody
  public Object handlerException(HttpServletRequest request, Exception ex){
    Map responseData = new HashMap<>();
    if(ex instanceof BusinessException){
      BusinessException businessException = (BusinessException)ex;
      responseData.put("errCode",businessException.getErrCode());
      responseData.put("errMsg",businessException.getErrMsg());
    }else{
      responseData.put("errCode", EmBusinessError.UNKNOWN_ERROR.getErrCode());
      responseData.put("errMsg",EmBusinessError.UNKNOWN_ERROR.getErrMsg());

    }
    return CommonReturnType.create(responseData,"fail");
  }
}

然后,UserController类需要继承BaseController类。

运行后,我们访问http://localhost:8090/user/getid=2,(id=2的数据是不存在的),可以看到页面为:

详解基于SpringBoot如何构建电商秒杀项目

为了程序的健壮性,我们在BaseController中添加了一个unknown error。我们可以手动地来测试一下这段代码是否起了作用:

修改UserController部分代码如下:

    if(userModel==null){
       userModel.setEncriptPassword("123");
       //throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
     }

运行后,我们再次访问http://localhost:8090/user/getid=2,可以看到页面为:

详解基于SpringBoot如何构建电商秒杀项目

看完这篇关于详解基于SpringBoot如何构建电商秒杀项目的文章,如果觉得文章内容写得不错的话,可以把它分享出去给更多人看到。


名称栏目:详解基于SpringBoot如何构建电商秒杀项目
浏览地址:http://scyanting.com/article/jopshd.html