扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
小编这次要给大家分享的是详解基于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 35 4.0.0 6 7org.example 8Spike 91.0-SNAPSHOT 10 11Spike 12 13http://www.example.com 14 1516 20 21org.springframework.boot 17spring-boot-starter-parent 182.0.5.RELEASE 1922 26 27UTF-8 231.8 241.8 2528 59 6029 32org.springframework.boot 30spring-boot-starter-web 3133 37mysql 34mysql-connector-java 355.1.6 3638 42com.alibaba 39druid 401.1.3 4143 47org.mybatis.spring.boot 44mybatis-spring-boot-starter 451.3.1 4648 53junit 49junit 504.11 51test 5254 58org.mybatis.generator 55mybatis-generator-core 561.3.5 5761 14462 14363 64 14265 68 69maven-clean-plugin 663.1.0 6770 73maven-resources-plugin 713.0.2 7274 77maven-compiler-plugin 753.8.0 7678 81maven-surefire-plugin 792.22.1 8082 85maven-jar-plugin 833.0.2 8486 89maven-install-plugin 872.5.2 8890 93 94 95maven-deploy-plugin 912.8.2 9296 99maven-site-plugin 973.7.1 98100 103 104maven-project-info-reports-plugin 1013.0.0 102105 140 141org.mybatis.generator 106mybatis-generator-maven-plugin 1071.3.5 108109 120110 114org.mybatis.generator 111mybatis-generator-core 1121.3.5 113115 119mysql 116mysql-connector-java 1175.1.6 118121 129122 128mybatis generator 123package 124125 127generate 126130 131 139true 132 133true 134 135136 src/main/resource/mybatis-generator.xml 137 138
步骤5:创建mysql底层的数据库与相关表格
1.创建数据库spike
2.创建一个user_info表格
3.创建一个user_password表格,并设置user_id为外键关联user_info的id
步骤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下多了两个文件:
dataobject包与dao包下生成了如下文件:
手动删除两个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:补全框架结构:
步骤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,可以看到页面上输出了:
步骤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){ MapresponseData = 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的数据是不存在的),可以看到页面为:
为了程序的健壮性,我们在BaseController中添加了一个unknown error。我们可以手动地来测试一下这段代码是否起了作用:
修改UserController部分代码如下:
if(userModel==null){ userModel.setEncriptPassword("123"); //throw new BusinessException(EmBusinessError.USER_NOT_EXIST); }
运行后,我们再次访问http://localhost:8090/user/getid=2,可以看到页面为:
看完这篇关于详解基于SpringBoot如何构建电商秒杀项目的文章,如果觉得文章内容写得不错的话,可以把它分享出去给更多人看到。
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流