Springboot简易商城项目后端搭建流程

编程入门 行业动态 更新时间:2024-10-11 23:22:38

Springboot<a href=https://www.elefans.com/category/jswz/34/1769136.html style=简易商城项目后端搭建流程"/>

Springboot简易商城项目后端搭建流程

Springboot简易商城项目后端搭建流程

1,环境准备

  • IntelliJ IDEA 2022.3
  • Maven-3.6.3
  • MySQL Server 8.0
  • jdk1.8.0_231
  • PostMan
  • navicat

2,数据库表建立

1,tb_user表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for tb_user
-- ----------------------------
DROP TABLE IF EXISTS `tb_user`;
CREATE TABLE `tb_user`  (`user_id` int(0) NOT NULL AUTO_INCREMENT,`username` varchar(15) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`password` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`address` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`phone` varchar(11) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`user_id`) USING BTREE,UNIQUE INDEX `username`(`username`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1011 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of tb_user
-- ----------------------------
INSERT INTO `tb_user` VALUES (1001, 'wzc', '123456', 'fujian', '12345678901');SET FOREIGN_KEY_CHECKS = 1;

2,tb_good表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for tb_good
-- ----------------------------
DROP TABLE IF EXISTS `tb_good`;
CREATE TABLE `tb_good`  (`good_id` int(0) NOT NULL,`good_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`good_img` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`good_info` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`good_price` decimal(10, 2) NULL DEFAULT NULL,PRIMARY KEY (`good_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of tb_good
-- ----------------------------
INSERT INTO `tb_good` VALUES (101, '萨摩耶', 'images/aside1.jpg', '微笑治愈小暖男', 100.00);
INSERT INTO `tb_good` VALUES (102, '金毛', 'images/warm1.jpg', '温暖体贴小天使', 200.00);
INSERT INTO `tb_good` VALUES (103, '阿拉斯加', 'images/warm3.jpg', '体强力壮小保镖', 300.00);
INSERT INTO `tb_good` VALUES (104, '哈士奇', 'images/sb1.jpg', '鬼哭狼嚎让你又哭又笑', 400.00);
INSERT INTO `tb_good` VALUES (105, '柴犬', 'images/sb2.jpg', '古灵精怪让你又惊又跳', 500.00);
INSERT INTO `tb_good` VALUES (106, '柯基', 'images/sb3.jpg', '娇小可爱让你又欢又喜', 600.00);
INSERT INTO `tb_good` VALUES (107, '边牧', 'images/smart1.jpg', '智商过人', 700.00);
INSERT INTO `tb_good` VALUES (108, '德牧', 'images/smart2.jpg', '天生警察', 800.00);
INSERT INTO `tb_good` VALUES (109, '拉布拉多', 'images/smart3.jpg', '盲人向导', 900.00);SET FOREIGN_KEY_CHECKS = 1;

3,tb_cart表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for tb_cart
-- ----------------------------
DROP TABLE IF EXISTS `tb_cart`;
CREATE TABLE `tb_cart`  (`cart_id` int(0) NOT NULL AUTO_INCREMENT,`count` int(0) NULL DEFAULT NULL,`good_price` decimal(10, 2) NULL DEFAULT NULL,`good_total_price` decimal(10, 2) NULL DEFAULT NULL,`good_id` int(0) NOT NULL,`user_id` int(0) NULL DEFAULT NULL,`checked` tinyint(1) NULL DEFAULT 0,PRIMARY KEY (`cart_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of tb_cart
-- ----------------------------
INSERT INTO `tb_cart` VALUES (10001, 5, 100.00, 500.00, 101, 1001, 0);SET FOREIGN_KEY_CHECKS = 1;

4,tb_order表

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;-- ----------------------------
-- Table structure for tb_order
-- ----------------------------
DROP TABLE IF EXISTS `tb_order`;
CREATE TABLE `tb_order`  (`order_id` int(0) NOT NULL AUTO_INCREMENT,`good_id` int(0) NULL DEFAULT NULL,`user_id` int(0) NULL DEFAULT NULL,`create_time` datetime(0) NULL DEFAULT NULL,`price` decimal(10, 2) NULL DEFAULT NULL,`count` int(0) NULL DEFAULT NULL,`total_price` decimal(10, 2) NULL DEFAULT NULL,PRIMARY KEY (`order_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 100158 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of tb_order
-- ----------------------------
INSERT INTO `tb_order` VALUES (100001, 107, 1001, '2023-05-20 21:32:21', 100.00, 1, 100.00);
INSERT INTO `tb_order` VALUES (100159, 110, 1004, '2023-05-20 16:07:46', 200.00, 1, 400.00);
INSERT INTO `tb_order` VALUES (100160, 108, 1002, '2023-05-20 16:08:22', 200.00, 3, 600.00);
INSERT INTO `tb_order` VALUES (100161, 108, 1004, '2023-05-20 16:09:35', 200.00, 3, 600.00);
INSERT INTO `tb_order` VALUES (100162, 108, 1003, '2023-05-20 16:09:54', 200.00, 3, 600.00);
INSERT INTO `tb_order` VALUES (100163, 102, 1005, '2023-05-20 21:52:06', 200.00, 5, 1000.00);SET FOREIGN_KEY_CHECKS = 1;

3,Springboot项目搭建

1,添加依赖pom.xml

<!--    1.继承spring boot父项目-->
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.5.4</version><relativePath/> <!-- lookup parent from repository -->
</parent><!--    2.依赖管理-->
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.2.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!--swagger 3.0依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency><!-- jwt依赖--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.14.0</version></dependency><!--读取配置依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>2.7.3</version></dependency><!--swagger 3.0依赖--><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency>
</dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-resources-plugin</artifactId><version>3.1.0</version></plugin></plugins>
</build>

2,主程序

@SpringBootApplication
public class VueUpdateApplication {public static void main(String[] args) {SpringApplication.run(VueUpdateApplication.class, args);}}

3,application.yml配置文件

server:port: 80spring:datasource:druid:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://你自己的mysql地址与端口/vue1?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8username: rootpassword: 密码mybatis-plus:global-config:db-config:table-prefix: tb_id-type: autoconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

4,包构建

  1. config包:主要放置一些配置类,如过滤器拦截器等
  2. controller包:控制层的包,对外提供http接口的代码都在这个包下
  3. mapper包(或者dao包):控制层的包,对外提供http接口的代码都在这个包下
  4. entity包(model包或者pojo包):实体类的包,将实体类与数据表对应的类都放在这个包下
  5. service包:业务层包,将功能业务的实现逻辑都放在这个包下,主要实现的是复杂的业务逻辑
  6. utils包:公共应用类的包,比如自己封装了一些公用的类

5,mybatis映射文件mapper

公共应用类的包,比如自己封装了一些公用的类

6,在aaplication.yml添加mapper映射配置

mybatis:mapper-locations: classpath:/mapper/*

如使用mybatis-plus,则不需要使用上面的配置,mybatis-plus具体配置如下:

mybatis-plus:global-config:db-config:table-prefix: tb_id-type: autoconfiguration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

如使用myabtis-plus,需要自己写sql语句,则需要设置配置文件

mybatis-plus:mapper-locations: classpath:/mapper/*

4,response返回json统一模版规范

1,数据体

  1. code状态码:http状态码
  2. message消息:说明信息
  3. data数据体:接口返回数据,这份最为核心
  4. 接口状态:非必要,用于指示接口是否正常返回数据

2,在utils包里创建枚举类

public enum ResultCodeEnum {SUCCESS(200, "成功"), // 成功FAIL(400, "失败"), // 失败BAD_REQUEST(400, "Bad Request"),UNAUTHORIZED(401, "认证失败"), // 未认证 unauthorizedNOT_FOUND(404, "接口不存在"), // 接口不存在INTERNAL_SERVER_ERROR(500, "系统繁忙"), // 服务器内部错误METHOD_NOT_ALLOWED(405, "方法不被允许"),/*参数错误:1001-1999*/PARAMS_IS_INVALID(1001, "参数无效"),PARAMS_IS_BLANK(1002, "参数为空"),USER_IS_EXITES(1003, "用户名已存在");;/*** 响应状态码*/private Integer code;/*** 响应信息*/private String message;ResultCodeEnum(Integer code, String msg) {this.code = code;this.message = msg;}public Integer getCode() {return code;}public String getMessage() {return message;}
}

3,在utils包里创建统一返回模版类

@Data
// 一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才能被序列化。
public class Result<T> implements Serializable {/*** 是否响应成功*/private Boolean success;/*** 响应状态码*/private Integer code;/*** 响应数据*/private T data;/*** 错误信息*/private String message;// 构造器开始/*** 无参构造器(构造器私有,外部不可以直接创建)*/private Result() {this.code = 200;this.success = true;}/*** 有参构造器* @param obj*/private Result(T obj) {this.code = 200;this.data = obj;this.success = true;}/*** 有参构造器* @param resultCode*/private Result(ResultCodeEnum resultCode) {this.success = false;this.code = resultCode.getCode();this.message = resultCode.getMessage();}/*** 有参构造器* @param resultCode* @param message*/private Result(ResultCodeEnum resultCode,String message) {this.success = false;this.code = resultCode.getCode();this.message = message;}/*** 通用返回成功(没有返回结果)* @param <T>* @return*/public static<T> Result<T> success(){return new Result();}/*** 返回成功(有返回结果)* @param data* @param <T>* @return*/public static<T> Result<T> success(T data){return new Result<T>(data);}/*** 通用返回失败* @param resultCode* @param <T>* @return*/public static<T> Result<T> failure(ResultCodeEnum resultCode){return  new Result<T>(resultCode);}/*** 通用返回失败* @param resultCode* @param message* @param <T>* @return*/public static<T> Result<T> failure(ResultCodeEnum resultCode,String message){return  new Result<T>(resultCode,message);}}

5,jwt

1,添加JWTUtils应用工具类

@Component
@ConfigurationProperties(prefix = "jwt")
public class JWTUtils {/*** 生成token  格式:header.payload.singature*/private static String SING;private static Integer expireTime;public void setSING(String SING) {JWTUtils.SING = SING;}public void setExpireTime(Integer expireTime) {JWTUtils.expireTime = expireTime;}/*** 根据用户id和用户名获取token* @param userId* @param userName* @return*/public static String getToken(String userId, String userName) {Calendar instance = Calendar.getInstance();// 单位分钟instance.add(Calendar.MINUTE, expireTime);//创建jwt builderJWTCreator.Builder builder = JWT.create();// payloadMap<String, String> payload = new HashMap<>();payload.put("id",userId);payload.put("name",userName);payload.forEach((k, v) -> {builder.withClaim(k, v);});String token = builder.withExpiresAt(instance.getTime())  //指定令牌过期时间.sign(Algorithm.HMAC256(SING));  // signreturn token;}/***  验证token  合法性* @param token* @return*/public static DecodedJWT verify(String token) {return JWT.require(Algorithm.HMAC256(SING)).build().verify(token);}}

2,在application.yml添加jwt的密钥和有效时间配置

jwt:SING: "202012901132" #密钥expireTime: 30 #token有效时间 (分钟)

6,用户登录注册实例开发

1,在entity包下创建User实体类

@Data
public class User {private Integer userId;private String username;private String password;private String address;private String phone;
}

2,在dao中创建数据映射接口

继承myabtis-plus的BaseMapper

@Mapper
public interface UserDao extends BaseMapper<User> {}

3,service包中创建接口和实现类

​ IUserService继承IService

public interface IUserService extends IService<User> {}

​ 实现类继承ServiceImpl<UserDao, User>,实现IUserService接口

@Service
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements IUserService {}

4,controller包中创建接口

@RestController
@RequestMapping("/users")
@Slf4j
public class UserController {@Autowiredprivate IUserService userService;/*** 注册功能** @param user* @return*/@PostMapping("/register")//  @RequestBody 请求体参数public Result register(@RequestBody User user) {// 根据注册的用户名查询用户QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", user.getUsername());User one = userService.getOne(wrapper);//  1.用户已存在if (one != null) {return Result.failure(ResultCodeEnum.USER_IS_EXITES);}// 2. 用户不存在,则注册用户userService.save(user);return Result.success("注册用户成功");}/*** 登录功能* @param user* @return*/@PostMapping("/login")public Result login(@RequestBody User user) {// 根据密码和用户名查询用户是否存在QueryWrapper<User> wrapper = new QueryWrapper<>();wrapper.eq("username", user.getUsername());wrapper.eq("password", user.getPassword());User one = userService.getOne(wrapper);// 1.用户名密码不正确if (one == null) {return Result.failure(ResultCodeEnum.UNAUTHORIZED, "用户名或密码错误!");} else {    // 2.用户名密码正确String userId = String.valueOf(one.getUserId());// 根据用户名和用户id生成使用写好的工具类生成tokenString token = JWTUtils.getToken(userId, one.getUsername());// 封装返回前端的data数据Map<String, String> userMap = new HashMap<String, String>();userMap.put("userId", userId);userMap.put("userName", one.getUsername());userMap.put("token", token);return Result.success(userMap);}}}

7,商品功能开发实例

1,在domain包下创建Good实体类

@Data
public class Good {private int goodId;private String goodName;private String goodImg;private String goodInfo;private double goodPrice;
}

2,在dao中创建数据映射接口

@Mapper
public interface GoodDao extends BaseMapper<Good> {
}

3,service包中创建接口和实现类

public interface IGoodService extends IService<Good> {
}

实现类

@Service
public class GoodServiceImpl extends ServiceImpl<GoodDao, Good> implements IGoodService {}

4,controller包中创建接口

@RestController
@RequestMapping("/goods")
public class GoodsController {@AutowiredGoodsService goodsService;@GetMapping("/all")public Result getAllgoods(@RequestParam(name = "pageNum") Integer pageNum,@RequestParam(name = "pageSize") Integer pageSize){PageInfo<Goods> pageInfo = goodsService.getAllgoods(pageNum,pageSize);return Result.success(pageInfo);}@GetMapping("/detail/{gid}")public Result detail( @PathVariable(name = "gid")Integer gid){Goods goods = goodsService.getGoodById(gid);return Result.success(goods);}@GetMapping("/search")public Result search( @RequestParam(name = "gname") String gname,@RequestParam(name = "pageNum") Integer pageNum,@RequestParam(name = "pageSize") Integer pageSize){PageInfo<Goods> pageInfo = goodsService.searchGoodsByName(gname,pageNum,pageSize);return Result.success(pageInfo);}
}

5,在config中添加配置类,使得前端能通过url读取到静态图片

​ 在application.yml添加如下变量,真实文件路径,和图片前缀

file:save-path: "实际文件路径"
image:prefix-url: "http://ip:端口"

​ 新建WebConfig配置类,将访问路径映射到文件真实的存储路径

@Configuration
public class WebConfig implements WebMvcConfigurer {@Value("${file.save-path}")String filePath;@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//其中images表示访问的前缀。  "file:"是文件真实的存储路径registry.addResourceHandler("/images/**").addResourceLocations("file:"+filePath);WebMvcConfigurer.super.addResourceHandlers(registry);}
}

​ 在controller类添加图片路径拼接的功能,将数据库读到的路径,拼接成“http:127.0.0.1:8080/images/XXX.jpg”

@RestController
@RequestMapping("/goods")
public class GoodController {@AutowiredIGoodService goodService;@Value("${image.prefix-url}")String imgUrl;/*** 分页查询(可以根据商品名(name)查询,name为空则查询全部)* @param page* @param pageSize* @param name* @return*/@GetMapping("/page")public Result getAllgoods(@RequestParam(name = "page")int page,@RequestParam(name = "pageSize") int pageSize,@RequestParam(name = "name") String name){// 构造分页构造器对象,分页查询到的数据赋值给pageInfoIPage<Good> pageInfo = new Page<>(page,pageSize);// 条件构造器QueryWrapper<Good> queryWrapper = new QueryWrapper<>();// 添加过滤条件,先判断name是否为空queryWrapper.like(name != null,"good_name",name);// 执行分页查询goodService.page(pageInfo,queryWrapper);// 拼接图片访问路径pageInfo.getRecords().forEach(good -> {String imgPath = good.getGoodImg();good.setGoodImg(imgUrl + imgPath);});// 未查询到商品数据if(pageInfo.getRecords().isEmpty()) {return Result.failure(ResultCodeEnum.FAIL);}// 查询到商品数据return Result.success(pageInfo);}/*** 根据商品id查询商品信息* @param goodId* @return*/@GetMapping("/detail/{goodId}")public Result detail( @PathVariable(name = "goodId")Integer goodId){QueryWrapper<Good> queryWrapper = new QueryWrapper<>();queryWrapper.eq("good_id",goodId);Good one = goodService.getOne(queryWrapper);// 拼接图片访问路径String imgPath = one.getGoodImg();one.setGoodImg(imgUrl + imgPath);return Result.success(one);}}

8,购物车功能开发实例

1,在domain包下创建Cart实体类

@Data
public class Cart {@TableId(type = IdType.AUTO)private Integer cartId;private int count;private double goodPrice;private double goodTotalPrice;private int goodId;private int userId;private boolean checked;
}

2,在dao中创建数据映射接口

@Mapper
public interface CartDao extends BaseMapper<Cart> {}

3,service包中创建接口和实现类

public interface CartService extends IService<Cart> {Cart insertCart(Cart cart);IPage<Cart> getAllCart(Integer uid, Integer pageNum, Integer pageSize);int payCart(Integer uid);}
@Service
public class CartServiceImpl extends ServiceImpl<CartDao, Cart> implements CartService {@Autowired(required = false)CartDao cartDao;@Autowired(required = false)GoodDao goodDao;@Autowired(required = false)OrderDao orderDao;/*** 添加商品至购物车* @param cart* @return*/@Overridepublic Cart insertCart(Cart cart) {// 1.根据用户id和商品id查询该商品是否已经存在该用户的购物车中QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();queryWrapper.eq("user_id",cart.getUserId());queryWrapper.eq("good_id",cart.getGoodId());// cart1为从购物车中查询到的商品Cart cart1 = cartDao.selectOne(queryWrapper);// 根据商品id获取商品详细信息Good good = goodDao.selectById(cart.getGoodId());// 2.存在,修改数量if (cart1 != null) {// 添加的数量 + 原本存在的数量int number = cart.getCount() + cart1.getCount();cart1.setCount(number);// 重新计算价格并赋值double price = number * good.getGoodPrice();cart1.setGoodTotalPrice(price);QueryWrapper<Cart> queryWrapper1 = new QueryWrapper<>();queryWrapper1.eq("cart_id",cart1.getCartId());cartDao.update(cart1,queryWrapper1);return cart1;}// 3.不存在 加入购物车double price = cart.getCount() * good.getGoodPrice();cart.setGoodTotalPrice(price);cartDao.insert(cart);return cart1;}/*** 根据用户id分页查询购物车数据* @param uid* @param pageNum* @param pageSize* @return*/@Overridepublic IPage<Cart> getAllCart(Integer uid, Integer pageNum, Integer pageSize) {Page<Cart> pageInfo = new Page<>(pageNum,pageSize);QueryWrapper queryWrapper = new QueryWrapper<>();queryWrapper.eq("user_id",uid);// 根据用户id分页查询cartDao.selectPage(pageInfo,queryWrapper);return pageInfo;}// TODO 购物车中根据checked字段判断进行结算的功能还未实现/*** 结算购物车(需判断购物车中商品checked,为true才参与结算)* @param uid* @return*/@Overridepublic int payCart(Integer uid) {QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_id",uid);List<Cart> cartList = cartDao.selectList(queryWrapper);// 购物车数据为空if (cartList.size() == 0) {return 0;}// 购物车存在数据,根据所选项插入订单cartList.forEach(cart -> {double goodPrice = cart.getGoodPrice();int userId = cart.getUserId();int goodId = cart.getGoodId();double goodTotalPrice = cart.getGoodTotalPrice();int count = cart.getCount();Order order = new Order(goodId,userId,goodPrice,count,goodTotalPrice);orderDao.insert(order);});// 删除购物车return cartDao.delete(queryWrapper);}}

4,controller包中创建接口

@RestController
@RequestMapping("/carts")
public class CartController {@AutowiredCartService cartService;/*** 添加购物车* @param cart* @return*/@PostMapping("/insert")public Result insertCart(@RequestBody Cart cart){Cart cart1 = cartService.insertCart(cart);return Result.success(cart1);}/*** 分页查询购物车数据* @param userId* @param page* @param pageSize* @return*/@GetMapping("/page")public Result getAllCart(@RequestParam(name = "userId") Integer userId,@RequestParam(name = "page") Integer page,@RequestParam(name = "pageSize") Integer pageSize){IPage<Cart> cartIPage = cartService.getAllCart(userId, page, pageSize);return Result.success(cartIPage);}/*** 购物车+1或者-1* @param uid* @param gid* @param operate   操作数,-1为-1,1为+1* @return*/@PutMapping("/addone")public Result addCart(@RequestParam(name = "userId") Integer uid,@RequestParam(name = "goodId") Integer gid,@RequestParam(name = "operate") Integer operate){// 1.获取购物车中对应id的商品数据QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_id",uid);queryWrapper.eq("good_id",gid);Cart one = cartService.getOne(queryWrapper);// 2.修改改商品的数量、总价格,前端不允许数量为1的商品-1,所以不需要多做判断one.setCount(one.getCount() + operate);double totalPrice = one.getCount() * one.getGoodPrice();one.setGoodTotalPrice(totalPrice);// 更新数据库数据cartService.update(one,queryWrapper);return Result.success(one);}/*** 根据cart_id 勾选商品* @param id* @return*/@PutMapping("/checkone/{id}")public Result check(@PathVariable Integer id){Cart cart = cartService.getById(id);cart.setChecked(!cart.isChecked());// 根据商品id更新商品数据,进行更新的时候要注意接where条件,不然可能导致全部数据被修改boolean update = cartService.updateById(cart);return Result.success();}/*** 根据cartId删除单个购物车商品* @param id* @return*/@DeleteMapping("/deleteone/{id}")public Result deldeteOne(@PathVariable Integer id){boolean b = cartService.removeById(id);if (b) {return Result.success("删除成功");}return Result.failure(ResultCodeEnum.FAIL,"删除失败!");}/*** 根据用户id删除购物车全部数据* @param uid* @return*/@DeleteMapping("/deleteall/{uid}")public Result deldeteAll(@PathVariable Integer uid){QueryWrapper queryWrapper = new QueryWrapper();queryWrapper.eq("user_id",uid);boolean remove = cartService.remove(queryWrapper);if (remove) {return Result.success("删除成功");}return Result.failure(ResultCodeEnum.FAIL,"删除失败!");}// TODO 购物车中根据checked字段判断进行结算的功能还未实现/*** 结算购物车(需判断购物车中商品checked,为true才参与结算)* @param uid* @return*/@PostMapping("/pay/{uid}")public Result payAll(@PathVariable Integer uid){int res = cartService.payCart(uid);if(res >= 1){return Result.success();}else{return Result.failure(ResultCodeEnum.FAIL,"结算失败!");}}
}

9,订单功能开发实例

1,在domain包下创建Cart实体类

@Data
public class Order {@TableId(type = IdType.AUTO)private Integer orderId;private int goodId;private int userId;private LocalDateTime createTime;private double price;private int count;private double totalPrice;public Order() {}public Order(int goodId, int userId, double price, int count, double totalPrice) {this.createTime = LocalDateTime.now();this.goodId = goodId;this.userId = userId;this.price = price;this.count = count;this.totalPrice = totalPrice;}
}

2,在dao中创建数据映射接口

@Mapper
public interface OrderDao extends BaseMapper<Order> {
}

3,service包中创建接口和实现类

public interface IOrderService extends IService<Order> {
}
@Service
public class OrderServiceImpl extends ServiceImpl<OrderDao, Order> implements IOrderService {}

4,controller包中创建接口

@RestController
@RequestMapping("/orders")
public class OrderController {@Autowiredprivate IOrderService orderService;/*** 订单分页查询(根据用户id)** @param userId* @param pageNum* @param pageSize* @return*/@GetMapping("/page")public Result getAllOrders(@RequestParam(name = "userId") Integer userId,@RequestParam(name = "pageNum") Integer pageNum,@RequestParam(name = "pageSize") Integer pageSize) {// 构造分页构造器对象,分页查询到的数据赋值给pageInfoIPage<Order> pageInfo = new Page<>(pageNum, pageSize);// 条件构造器QueryWrapper<Order> queryWrapper = new QueryWrapper<>();queryWrapper.eq("user_id", userId);orderService.page(pageInfo, queryWrapper);return Result.success(pageInfo);}}

10,拦截器

1,JWT拦截器实现

​ 先获取请求头部的token,再通过验证令牌的工具类验证token是否正确

@Component
public class JWTInterceptors implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Map<String,Object> map = new HashMap<>();String message="";// 获取请求头中令牌String token = request.getHeader("token");try {// 验证令牌JWTUtils.verify(token);return true;  // 放行请求} catch (SignatureVerificationException e) {
//            e.printStackTrace();message="无效签名!";}catch (TokenExpiredException e){
//            e.printStackTrace();message="token过期";}catch (AlgorithmMismatchException e){
//            e.printStackTrace();message="算法不一致";}catch (Exception e){
//            e.printStackTrace();message="token 为空或无效!";}// 将HttpResult以json的形式响应到前台  HttpResult --> json  (jackson)ObjectMapper mapper = new ObjectMapper();String json = mapper.writeValueAsString(Result.failure(ResultCodeEnum.UNAUTHORIZED,message));response.setContentType("application/json;charset=UTF-8");response.getWriter().println(json);return false;}
}

2,拦截器在配置类中注册

​ 在WebConfig下实现WebMvcConfigurer的情况下重写addInterceptors方法

@Override
public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new JWTInterceptors()).addPathPatterns("/**")//所有接口进行拦截.excludePathPatterns("/users/login","/users/register","/goods/page") //登录、注册、首页放行.excludePathPatterns("/images/**"); //放行静态资源中的图片
}

11,跨域问题解决

1,跨域现象

​ 跨域:浏览器安全策略,拒绝不同源的数据

​ 源:协议+域名+端口

2,添加配置类解决跨域问题

​ config包下新建CrosConfig配置类

@Configuration
public class CrosConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration corsConfiguration = new CorsConfiguration();//1,允许任何来源corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*"));//2,允许任何请求头corsConfiguration.addAllowedHeader(CorsConfiguration.ALL);//3,允许任何方法corsConfiguration.addAllowedMethod(CorsConfiguration.ALL);//4,允许凭证corsConfiguration.setAllowCredentials(true);UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", corsConfiguration);return new CorsFilter(source);}
}

12,Swagger使用

swagger的依赖

<!--swagger 3.0依赖-->
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version>
</dependency>

1,添加配置类SwaggerConfig

@Configuration
@EnableOpenApi
public class SwaggerConfig {@Value("${swagger.enabled}")Boolean swaggerEnabled;@Beanpublic Docket docket() {return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo())// 是否开启swagger.enable(swaggerEnabled).select()// 过滤条件,扫描指定路径下的文件.apis(RequestHandlerSelectors.basePackage("ptumall.controller"))// 指定路径处理,PathSelectors.any()代表不过滤任何路径.paths(PathSelectors.any()).build().securitySchemes(Collections.singletonList(securityScheme())).securityContexts(Arrays.asList(tokenContext()));}private ApiInfo apiInfo() {/*作者信息*/Contact contact = new Contact("wzc", "", "947887238@qq");return new ApiInfo("ptu mall","ptu mall 测试接口文档","v1.0","",contact,"Apache 2.0",".0",new ArrayList());}@BeanSecurityScheme securityScheme() {return new ApiKey("token", "token", "header");}private SecurityContext tokenContext() {return SecurityContext.builder().securityReferences(Arrays.asList(SecurityReference.builder().scopes(new AuthorizationScope[0]).reference("token").build())).operationSelector(o -> o.requestMappingPattern().matches("/.*")).build();}
}

2,在application.yml开启swagger功能

swagger:enabled: true

3,拦截器放开swagger

​ 在WebConfig重写的addInterceptors方法中放行swagger

.excludePathPatterns("/swagger-resources/**","/swagger-ui/**", "/v3/**", "/error")//放行swagger

4,访问测试

http://ip:port/swagger-ui/index.html#/

5,实体类属性上添加注解,优化可视化显示

@ApiModel("用户实体类")
@Data
public class User {@ApiModelProperty(value = "用户id",required = false,example = "1001",hidden = true)@TableId(type = IdType.AUTO)private Integer userId;@ApiModelProperty(value = "用户名",required = true,example = "wzc")private String username;@ApiModelProperty(value = "用户密码",required = true,example = "123456")private String password;@ApiModelProperty(value = "地址",required = false,example = "福建")private String address;@ApiModelProperty(value = "电话",required = false,example = "12345678901")private String phone;
}
@ApiModel("订单实体类")
@Data
public class Order {@ApiModelProperty(value = "订单id",example = "100001")@TableId(type = IdType.AUTO)private Integer orderId;@ApiModelProperty(value = "商品id",example = "101")private int goodId;@ApiModelProperty(value = "用户id",example = "1001")private int userId;@ApiModelProperty(value = "创建时间")private LocalDateTime createTime;@ApiModelProperty(value = "商品价格",example = "100.00")private double price;@ApiModelProperty(value = "商品数量",example = "1")private int count;@ApiModelProperty(value = "总价格",example = "100.00")private double totalPrice;public Order() {}public Order(int goodId, int userId, double price, int count, double totalPrice) {this.createTime = LocalDateTime.now();this.goodId = goodId;this.userId = userId;this.price = price;this.count = count;this.totalPrice = totalPrice;}
}
@ApiModel("商品实体类")
@Data
public class Good {@ApiModelProperty(value = "商品id",example = "101")@TableId(type = IdType.AUTO)private Integer goodId;@ApiModelProperty(value = "商品名称",example = "萨摩耶")private String goodName;@ApiModelProperty(value = "商品图片",example = "http://127.0.0.1:8080/images/aside1.jpg")private String goodImg;@ApiModelProperty(value = "商品描述",example = "微笑治愈小暖男")private String goodInfo;@ApiModelProperty(value = "商品价格",example = "100.00")private double goodPrice;
}
@ApiModel("购物车实体类")
@Data
public class Cart {@ApiModelProperty(value = "购物车id",example = "10001")@TableId(type = IdType.AUTO)private Integer cartId;@ApiModelProperty(value = "数量",example = "1")private int count;@ApiModelProperty(value = "商品价格",example = "100.00")private double goodPrice;@ApiModelProperty(value = "商品总价格",example = "100.00")private double goodTotalPrice;@ApiModelProperty(value = "商品id",example = "101")private int goodId;@ApiModelProperty(value = "用户id",example = "1001")private int userId;@ApiModelProperty(value = "勾选状态(0为未勾选,1为勾选)",example = "0")private boolean checked;
}

6,在controller方法上添加注解,优化可视化显示

​ UserController

@Api(tags = "1-用户接口")
@RestController
@RequestMapping("/users")// 用户注册
@ApiOperation("用户注册")
@PostMapping("/register")// 用户登录
@ApiOperation("用户登录")
@PostMapping("/login")

​ GoodController

@Api(tags = "2-商品接口")
@RestController
@RequestMapping("/goods")// 分页获取商品首页列表(name有值可搜索)
@ApiOperation("分页获取商品首页列表(name有值可搜索)")@ApiImplicitParams(value = {@ApiImplicitParam(name = "name",value = "商品名称",dataTypeClass = String.class,required = false),@ApiImplicitParam(name = "pageNum",value = "当前页码",dataTypeClass = Integer.class,required = true,defaultValue = "1"),@ApiImplicitParam(name = "pageSize",value = "当前页数量",dataTypeClass = Integer.class,required = true,defaultValue = "4"),})// 根据商品id获取商品详情
@ApiOperation("根据商品id获取商品详情")@ApiImplicitParam(name = "goodId",value = "商品id",dataTypeClass = String.class,required = true,defaultValue = "101")@GetMapping("/detail/{goodId}")

​ CartController

@Api(tags = "3-购物车接口")
@RestController
@RequestMapping("/carts")// 加入购物车
@ApiOperation("加入购物车")@PostMapping("/insert")// 分页获取所有购物车商品
@ApiOperation("分页获取所有购物车商品")@ApiImplicitParams(value = {@ApiImplicitParam(name = "userId", value = "用户id", dataTypeClass = Integer.class, required = true, defaultValue = "1"),@ApiImplicitParam(name = "pageNum", value = "当前页码", dataTypeClass = Integer.class, required = true, defaultValue = "1"),@ApiImplicitParam(name = "pageSize", value = "当前页数量", dataTypeClass = Integer.class, required = true, defaultValue = "4"),})@GetMapping("/page")// 购物车商品加1或减1
@ApiOperation("购物车加1或者减1操作")@ApiImplicitParams(value = {@ApiImplicitParam(name = "userId", value = "用户id", dataTypeClass = Integer.class, required = true, defaultValue = "1001"),@ApiImplicitParam(name = "goodId", value = "商品id", dataTypeClass = Integer.class, required = true, defaultValue = "107"),@ApiImplicitParam(name = "operate", value = "操作数(1为加1,-1为减1)", dataTypeClass = Integer.class, required = true, defaultValue = "1"),})// 购物车勾选单件商品@ApiOperation("购物车勾选单件商品")@ApiImplicitParam(name = "id", value = "购物车id", dataTypeClass = Integer.class, required = true, defaultValue = "12345")@PutMapping("/checkone/{id}")// 购物车删除单件商品
@ApiOperation("购物车删除单件商品")@ApiImplicitParam(name = "id", value = "购物车id", dataTypeClass = Integer.class, required = true, defaultValue = "12345")@DeleteMapping("/deleteone/{id}")// 清空用户购物车
@ApiOperation("清空用户购物车")@ApiImplicitParam(name = "userId", value = "用户id", dataTypeClass = Integer.class, required = true, defaultValue = "1001")@DeleteMapping("/deleteall/{userId}")// 结算用户购物车
@ApiOperation("结算用户购物车")@ApiImplicitParam(name = "userId", value = "用户id", dataTypeClass = Integer.class, required = true, defaultValue = "1001")@PostMapping("/pay/{userId}")

​ OrderController

@Api(tags = "4-订单接口")
@RestController
@RequestMapping("/orders")// 分页获取订单列表
@ApiOperation("分页获取订单列表")@ApiImplicitParams(value = {@ApiImplicitParam(name = "userId",value = "用户id",dataTypeClass = Integer.class,required = true,defaultValue = "1001"),@ApiImplicitParam(name = "pageNum",value = "当前页码",dataTypeClass = Integer.class,required = true,defaultValue = "1"),@ApiImplicitParam(name = "pageSize",value = "当前页数量",dataTypeClass = Integer.class,required = true,defaultValue = "4"),})@GetMapping("/page")

7,swagger可视化的简单操作使用

​ 复制登录后的token

​ 点击Authorize

​ 将复制的token复制到Value框,点击Authorize

​ 请求头则带有登录后的token。

​ 即可正常测试,请求头需要带有token的接口

更多推荐

Springboot简易商城项目后端搭建流程

本文发布于:2024-03-15 01:12:24,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1737779.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:简易   后端   流程   商城   项目

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!