1.项目介绍
传统的 电商 单体架构 基于SpringBoot的电商项目开发
使用技术框架: SpringBoot、SpringTask、Mybatis、Mybatis-Plus、Redis、WebSocket
2.职权明确
管理员:店铺入驻审核、能对违规店铺进行禁用、管理员工信息、导出订单数据。
员工:查看商品订单、配送商品、回复客户咨询,处理客户投诉,提供售后服务。
店铺:上架商品、下架商品、查看店铺销售数据、选择开业或者停业
用户:查看商品留下浏览记录、可以购买商品、添加购物车、将商品移除购物车、申请开店铺、关注店铺、收藏商品、投诉举报、创建订单、支付订单、查看订单状态、取消订单、退货。
未登录用户:仅能浏览商品相关信息
3. 未登录用户模块
3.1 ProductController:(浏览商品信息)
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final IProductService productService;
//浏览商品
@GetMapping("/browse")
public R<ProductVO> browse(@RequestParam Long productId){
ProductVO productVO = productService.browse(productId);
return R.ok(productVO);
}
}
3.2 ProductServiceImpl:
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
private final ProductMapper productMapper;
private final BrowseRecordMapper browseRecordMapper;
@Override
public ProductVO browse(Long productId) {
Long userId = ThreadLocalUtil.get();
Product product = productMapper.selectById(productId);
//如果已登录,则会在该账号添加相应的浏览记录
if(userId != null){
BrowseRecord browseRecord = new BrowseRecord();
browseRecord.setUserId(userId);
browseRecord.setProductId(productId);
browseRecord.setLastViewTime(LocalDateTime.now());
//添加浏览记录
browseRecordMapper.save(browseRecord);
}
//返回商品信息
return BeanUtil.copyProperties(product,ProductVO.class);
}
}
4. 用户模块开发
4.1 用户基本的功能
(1)UserController:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final IUserService userService;
//登录
@PostMapping("/login")
public R<String> login(@RequestBody @Validated LoginDTO loginDTO){
String token = userService.login(loginDTO);
return R.ok(token);
}
//注册
@PostMapping("/register")
public R register(@RequestBody @Validated RegisterDTO registerDTO){
userService.register(registerDTO);
return R.ok();
}
//修改用户信息
@PutMapping("/update")
public R update(@RequestBody @Validated UserDTO userDTO){
UserVO userVO = userService.updateInfo(userDTO);
return R.ok(userVO);
}
//修改手机号码
@PutMapping("/modifyPhone")
public R modifyPhone(@RequestBody @Validated ModifyPhoneDTO modifyPhoneDTO){
userService.modifyPhone(modifyPhoneDTO);
return R.ok();
}
//获取用户信息
@GetMapping("/info")
public R<UserVO> info(){
Long userId = ThreadLocalUtil.get();
UserVO userVO = BeanUtil.copyProperties(userService.getById(userId),UserVO.class);
return R.ok(userVO);
}
}
(2)UserServiceImpl:
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService {
private final UserMapper userMapper;
private final RedisTemplate<String,Object> redisTemplate;
@Override
public String login(LoginDTO loginDTO) {
String phone = loginDTO.getPhone();
String password = loginDTO.getPassword();
User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
.eq(User::getPhone,phone));
if(user != null && Md5Util.checkPassword(password,user.getPassword())){
Map<String,Object> map = new HashMap<>();
map.put("userId",user.getId());
String token = JwtUtils.generateJwt(map);
//设置token验证的有效时间
redisTemplate.opsForValue().set(token,token,4, TimeUnit.HOURS);
return token;
}
return null;
}
@Override
public void register(RegisterDTO registerDTO) {
String redisCode = (String)redisTemplate.opsForValue().get("sms:register:"+registerDTO.getPhone());
User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
.eq(User::getPhone,registerDTO.getPhone()));
if(user==null && registerDTO.getCode().equals(redisCode)){
User newUser = new User();
newUser.setPhone(registerDTO.getPhone());
//默认性别为男生
newUser.setGender(0);
LocalDateTime currentTime = LocalDateTime.now();
newUser.setCreateTime(currentTime);
newUser.setUpdateTime(currentTime);
userMapper.insert(newUser);
}
}
@Override
public UserVO updateInfo(UserDTO userDTO) {
Long userId = ThreadLocalUtil.get();
User user = User.builder()
.id(userId)
.username(userDTO.getUsername())
.gender(userDTO.getGender())
.age(userDTO.getAge())
.address(userDTO.getAddress())
.email(userDTO.getEmail())
.avatar(userDTO.getAvatar()).build();
userMapper.updateById(user);
return BeanUtil.copyProperties(user,UserVO.class);
}
@Override
public void modifyPhone(ModifyPhoneDTO modifyPhoneDTO) {
Long userId = ThreadLocalUtil.get();
String code = modifyPhoneDTO.getCode();
String oldPhone = userMapper.getPhoneById(userId);
String redisCode = (String) redisTemplate.opsForValue().get("sms:modify_phone:"+ oldPhone);
if(redisCode != null && redisCode.equals(code)){
String newPhone = modifyPhoneDTO.getNewPhone();
userMapper.update(new LambdaQueryWrapper<User>()
.eq(User::getId,userId)
.eq(User::getPhone,newPhone));
}
}
}
4.2 购买商品(购买单个商品)、收藏商品
(1)ProductController:
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final IProductService productService;
//直接购买
@PostMapping("/purchase")
public R purchase(@RequestBody ProductCountDTO productCountDTO){
productService.purchase(productCountDTO);
return R.ok();
}
//收藏商品
@PostMapping("/favorite")
public R favorite(@RequestParam Long productId){
productService.favorite(productId);
return R.ok();
}
}
(2)ProductServiceImpl
@Service
@RequiredArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
private final ShopMapper shopMapper;
private final ProductMapper productMapper;
private final OrderItemMapper orderItemMapper;
private final OrderMapper orderMapper;
private final UserMapper userMapper;
@Override
public void purchase(ProductPurchaseDTO productPurchaseDTO) {
Product product = productMapper.selectById(productPurchaseDTO.getProductId());
BigDecimal subtotal = product.getPrice().multiply(BigDecimal.valueOf(productPurchaseDTO.getCount()));
//商品的库存减掉数量
product.setStock(product.getStock() - 1);
productMapper.updateById(product);
OrderItem orderItem = OrderItem.builder()
.price(product.getPrice())
.count(productPurchaseDTO.getCount())
.productId(product.getId())
.subtotal(subtotal)
.build();
//添加订单中的单个商品
orderItemMapper.insert(orderItem);
List<OrderItem> list = new ArrayList<>();
//将订单中的单个商品加入总订单中
list.add(orderItem);
Long userId = ThreadLocalUtil.get();
Order order = Order.builder()
.orderItems(list)
.userId(userId)
.status(OrderConstant.NOT_PAY)
.updateTime(LocalDateTime.now())
.createTime(LocalDateTime.now())
.totalAmount(subtotal)
.receiverName(productPurchaseDTO.getReceiverName())
.receiverAddress(productPurchaseDTO.getReceiverAddress())
.receiverPhone(productPurchaseDTO.getReceiverPhone())
.build();
//添加订单
orderMapper.insert(order);
}
@Override
public void favorite(Long productId) {
Long userId = ThreadLocalUtil.get();
User user = new User();
user.setId(userId);
user.setFavorite(user.getFavorite() != null ? user.getFavorite() : new ArrayList<>());
user.getFavorite().add(productId);
userMapper.updateById(user);
}
}
4.3 申请开店铺、关注店铺
(1)ShopController:
@RestController
@RequestMapping("/shop")
@RequiredArgsConstructor
public class ShopController {
private final IShopService shopService;
//申请店铺
@PostMapping("/applyShop")
public R applyShop(@RequestBody ShopDTO shopDTO){
shopService.applyShop(shopDTO);
return R.ok();
}
//关注店铺
@PostMapping("/follow")
public R follow(@RequestParam Long shopId){
shopService.follow(shopId);
return R.ok();
}
}
(2)ShopServiceImpl:
@Service
@RequiredArgsConstructor
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
private final ShopMapper shopMapper;
private final UserMapper userMapper;
@Override
public void follow(Long shopId) {
Long userId = ThreadLocalUtil.get();
User user = userMapper.selectById(userId);
user.setId(userId);
user.setFollow(user.getFollow() != null ? user.getFollow() : new ArrayList<>());
user.getFollow().add(shopId);
userMapper.updateById(user);
Shop shop = shopMapper.selectById(shopId);
shopMapper.update(new LambdaUpdateWrapper<Shop>()
.eq(Shop::getId,shopId)
.set(Shop::getFansNumber,shop.getFansNumber()+1));
}
@Override
public void applyShop(ShopDTO shopDTO) {
Shop shop = BeanUtil.copyProperties(shopDTO,Shop.class);
shop.setUserId(ThreadLocalUtil.get());
shop.setStatus(ShopConstant.APPLY_SHOP);
shop.setFansNumber(0);
shopMapper.insert(shop);
}
}
4.4 关注店铺、收藏商品
(1)UserController:
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final IUserService userService;
//关注店铺
@PostMapping("/follow")
public R follow(@RequestParam Long shopId){
userService.follow(shopId);
return R.ok();
}
//收藏商品
@PostMapping("/favorite")
public R favorite(@RequestParam Long productId){
userService.favorite(productId);
return R.ok();
}
}
(2)UserServiceImpl:
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements IUserService {
private final ShopMapper shopMapper;
private final UserMapper userMapper;
@Override
public void follow(Long shopId) {
Long userId = ThreadLocalUtil.get();
User user = userMapper.selectById(userId);
user.setId(userId);
user.setFollow(user.getFollow() != null ? user.getFollow() : new ArrayList<>());
user.getFollow().add(shopId);
userMapper.updateById(user);
Shop shop = shopMapper.selectById(shopId);
shopMapper.update(new LambdaUpdateWrapper<Shop>()
.eq(Shop::getId,shopId)
.set(Shop::getFansNumber,shop.getFansNumber()+1));
}
@Override
public void favorite(Long productId) {
Long userId = ThreadLocalUtil.get();
User user = new User();
user.setId(userId);
user.setFavorite(user.getFavorite() != null ? user.getFavorite() : new ArrayList<>());
user.getFavorite().add(productId);
userMapper.updateById(user);
}
}
4.6 添加购物车、将商品移除购物车(选择)、直接清空(从购物车中移除所有商品)、从购物车中进行购买(购买多个商品)
(1)CartController:
@RestController
@RequestMapping("/cart")
@RequiredArgsConstructor
public class CartController {
private final ICartService cartService;
//将商品加入购物车
@PostMapping("/save")
public R save(@RequestParam CartDTO cartDTO){
cartService.saveCart(cartDTO);
return R.ok();
}
//移除购物车
@PostMapping("/remove")
public R remove(@RequestParam List<Long> cartIds){
cartService.removeFromCart(cartIds);
return R.ok();
}
//清空购物车
@PostMapping("/clear")
public R clear(@RequestParam Long userId){
cartService.clear(userId);
return R.ok();
}
//购买
@PostMapping("/buy")
public R buy(@RequestParam List<Long> cartIds){
cartService.buy(cartIds);
return R.ok();
}
}
(2)CartServiceImpl:
@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {
private final CartMapper cartMapper;
private final OrderItemMapper orderItemMapper;
private final OrderMapper orderMapper;
private final ProductMapper productMapper;
@Override
public void clear(Long userId) {
cartMapper.clear(userId);
}
@Override
public void removeFromCart(List<Long> cartIds) {
cartMapper.deleteBatchIds(cartIds);
}
@Override
public void buy(CartBuyDTO cartBuyDTO) {
List<Cart> carts = cartBuyDTO.getCarts();
Long userId = ThreadLocalUtil.get();
Order order = Order.builder()
.receiverName(cartBuyDTO.getReceiverName())
.receiverAddress(cartBuyDTO.getReceiverAddress())
.receiverPhone(cartBuyDTO.getReceiverPhone())
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.status(OrderConstant.NOT_PAY)
.userId(userId)
.build();
List<OrderItem> orderItems = new ArrayList<>();
carts.forEach(cart -> {
Product product = productMapper.selectById(cart.getProductId());
OrderItem orderItem = new OrderItem();
orderItem.setCount(cart.getCount());
orderItem.setPrice(product.getPrice());
orderItem.setProductId(product.getId());
orderItem.setSubtotal(product.getPrice().multiply(BigDecimal.valueOf(cart.getCount())));
orderItemMapper.insert(orderItem);
orderItems.add(orderItem);
});
order.setOrderItems(orderItems);
orderMapper.insert(order);
}
@Override
public void saveCart(CartDTO cartDTO) {
Cart cart = BeanUtil.copyProperties(cartDTO,Cart.class);
cartMapper.insert(cart);
}
}
5. 员工权限模块开发
// 暂时没有开发员工模块
6.店铺权限模块的开发
6.1 上架商品、下架商品、更新商品信息
(1)ProductController:
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final IProductService productService;
//店铺上架商品
@PostMapping("/save")
public R save(@RequestBody ProductDTO productDTO){
productService.saveProduct(productDTO);
return R.ok();
}
//店铺下架商品
@DeleteMapping("/remove")
public R remove(@RequestParam List<Long> productIds){
productService.removeProduct(productIds);
return R.ok();
}
//店铺更新商品信息->同时更新订单对应的商品信息
@PostMapping("/update")
public R update(@RequestBody ProductDTO productDTO){
productService.updateProductInfo(productDTO);
return R.ok();
}
}
(2)ProductServiceImpl:
6.2 改变营业状态(开业或停业)
(1)ShopController:
@RestController
@RequestMapping("/shop")
@RequiredArgsConstructor
public class ShopController {
private final IShopService shopService;
//对店铺进行停业和开业
@PutMapping("/changeStatus")
public R changeStatus(@RequestParam Long shopId){
shopService.changeStatus(shopId);
return R.ok();
}
}
(2)ShopServiceImpl:
@Service
@RequiredArgsConstructor
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
private final ShopMapper shopMapper;
@Override
public void changeStatus(Long shopId) {
shopMapper.changeStatus(shopId);
}
}
(3)ShopMapper:
public interface ShopMapper extends BaseMapper<Shop> {
void changeStatus(Long shopId);
}
(4)ShopMapper.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">
<mapper namespace="com.etc.shop.mapper.ShopMapper">
<update id="changeStatus" parameterType="java.lang.Long">
update shop
<set>
<if test="status == 1">status = 2</if>
<if test="status == 2">status = 1</if>
</set>
<where>
id = #{shopId}
</where>
</update>
</mapper>
6.3 导出店铺销售额数据
//导出数据功能暂时没有开发
(1)ReportController:
(2)ReportServiceImpl:
7. 管理员权限模块的开发
7.1 管理员工信息
(1)EmployeeController:
@RestController
@RequestMapping("/employee")
@RequiredArgsConstructor
public class EmployeeController {
private final IEmployeeService employeeService;
//员工登录
@PostMapping("/login")
public R<String> login(@RequestBody LoginDTO loginDTO){
return R.ok(employeeService.login(loginDTO));
}
//新增员工
@PostMapping("/save")
public R save(@RequestBody EmployeeDTO employeeDTO){
employeeService.saveEmployee(employeeDTO);
return R.ok();
}
//删除员工
@DeleteMapping("/remove")
public R remove(@RequestParam Long employeeId){
employeeService.removeById(employeeId);
return R.ok();
}
//修改员工信息
@PutMapping("/update")
public R update(@RequestParam EmployeeDTO employeeDTO){
employeeService.updateInfo(employeeDTO);
return R.ok();
}
}
(2)EmployeeServiceImpl:
@Service
@RequiredArgsConstructor
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements IEmployeeService {
private final RedisTemplate<String,Object> redisTemplate;
private final EmployeeMapper employeeMapper;
@Override
public void saveEmployee(EmployeeDTO employeeDTO) {
Employee employee = BeanUtil.copyProperties(employeeDTO,Employee.class);
employee.setEntryTime(LocalDateTime.now());
employee.setUpdateTime(LocalDateTime.now());
employeeMapper.insert(employee);
}
@Override
public void updateInfo(EmployeeDTO employeeDTO) {
Employee employee = BeanUtil.copyProperties(employeeDTO,Employee.class);
employee.setUpdateTime(LocalDateTime.now());
employeeMapper.updateById(employee);
}
@Override
public String login(LoginDTO loginDTO) {
String phone = loginDTO.getPassword();
String password = loginDTO.getPassword();
Employee employee = employeeMapper.selectOne(new LambdaQueryWrapper<Employee>().eq(Employee::getPhone,phone));
if(employee != null && Md5Util.checkPassword(password,employee.getPassword())){
Map<String,Object> map = new HashMap<>();
map.put("employId",employee.getId());
String token = JwtUtils.generateJwt(map);
redisTemplate.opsForValue().set(token,token,4, TimeUnit.HOURS);
return token;
}
return null;
}
}
7.2 对店铺进行审核、对违规的店铺进行禁用
(1)ShopController:
@RestController
@RequestMapping("/shop")
@RequiredArgsConstructor
public class ShopController {
private final IShopService shopService;
//审核通过入驻的店铺
@PostMapping("/auditShop")
public R auditShop(@RequestParam Long shopId){
shopService.auditShop(shopId);
return R.ok();
}
//对店铺进行禁用和解除禁用状态
@PutMapping("/changeStatusByBan")
public R changeStatusByBan(@RequestParam Long shopId){
shopService.changeStatusByBan(shopId);
return R.ok();
}
}
(2)ShopServiceImpl:
@Service
@RequiredArgsConstructor
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
private final ShopMapper shopMapper;
@Override
public void changeStatusByBan(Long shopId) {
shopMapper.changeStatusByBan(shopId);
}
@Override
public void auditShop(Long shopId) {
shopMapper.update(new LambdaUpdateWrapper<Shop>()
.eq(Shop::getId,shopId)
.set(Shop::getStatus,ShopConstant.OPEN_SHOP));
}
}