该项目开始是要求我们使用JavaWeb(java+jsp+servlet+MySQL+jdbc+css+js+jQuery)实现,但我学过一丢丢的框架,就改用了SpringBoot+Vue实现。
注意!!!!!代码中的serverIp我设置的我服务器的IP,所以不在服务器上面应该是localhost!!!!!!!!
目录
1. 产品介绍
2. 产品面向的用户群体
3. 产品的范围
4. 产品中的角色
5. 产品的功能需求
5.1 功能性需求分类
5.2功能层次结构图
6. 产品的非功能性需求
6.1 用户界面需求
6.2 软硬件环境需求
6.3 产品质量需求
数据库设计:
前台页面:
在线商城首页:
编辑
首页Home.vue源代码:
商品详情页:
编辑 源代码Detail.Vue
我的购物车:
我的订单:
返回数据:
个人信息:
源代码Person.vue
联系商家:
后台页面:
核心代码:
1.UserController
2.TokenUtils
3.CartController
4.EchartsController
5.FileController
6.MybatisPlusConfig
7.Constants
对于网上商城,其最大好处是要能给用户带来最大的便捷,这种便捷不仅体现在网络之外的物流、商品的折扣等,更要体现在进行网络操作时的易用性,能够模拟用户的购物行为,营造一种尽量真实、贴切的用户购物过程。所以,在设计网络商城时,最重要的就是完成“用户功能”。其次,对众多商品、订单、用户信息的网络管理,对于网站经营者的经营效率的意义,也是不言而喻的,这些则可以称为“管理功能”。
本系统主要面向系统管理员和普通用户。
(1)系统管理员:订单管理、用户管理、商品管理等。
(2)普通用户:主要使用的业务模块包括系统登录、注册、购买商品、查询订单。
本项目主要分为系统设置模块、用户管理模块、商品管理模块、购买商品管理模块、订单管理模块。
角色名称 |
职责描述 |
普通用户 |
注册,登录,添加购物车,商品付款 |
管理员 |
登录,注册,商品信息管理,用户信息管理 |
功能类别 |
功能名称 |
描述 |
用户管理 |
个人信息管理 |
管理用户的个人信息 |
用户管理 |
管理已存在用户 |
|
商品管理 |
增加商品 |
对商城的商品进行添加 |
删除商品 |
删除商城的在架商品 |
|
订单管理 |
订单详情管理 |
对订单进行处理,对已付款的订单进行发货,对发货的商品进行收货 |
订单支付 |
支付当前未付款的订单 |
|
查看商品 |
查看该笔订单的商品信息 |
|
购物车管理 |
添加购物车 |
添加商品到购物车 |
删除购物车 |
删除当前购物车内的商品 |
|
商品结算 |
结算购物车的商品 |
需求名称 |
详细要求 |
整体风格 |
以蓝色为主色调 |
兼容性 |
能在主流浏览器(火狐、谷歌、IE8+、360浏览器)上运行 |
需求名称 |
详细要求 |
开发语言 |
Java或.NET |
运行环境 |
Jdk1.6+或.NET Framework 3.5以上 |
数据库 |
Mysql5.0或者SqlServer 2005以上 |
操作系统 |
Windows Server2008 |
主要质量属性 |
详细要求 |
正确性 |
无数据计算错误,无流程错误 |
健壮性 |
程序出错后,系统能正常捕获异常,不会导致程序终止运行 |
可靠性 |
系统支持7*24无间断运行,不会因系统功能的复杂运算而导致系统崩溃 |
性能、效率 |
数据请求在0.2S内返回 |
易用性 |
功能使用,操作简单,避免繁琐的逻辑设定 |
清晰性 |
功能结果及名称清晰,避免用户误解 |
安全性 |
用户必须成功登陆后,根据权限才可使用对应的功能 |
可扩展性 |
提供良好的系统接口,支持后续功能的开发扩展 |
兼容性 |
兼容主流浏览器(火狐、谷歌、IE8+、360浏览器) |
可移植性 |
能较好部署到其他版本的Windows操作系统上 |
1.1 数据库系统:
SQL Server 2008 / My SQL,服务器为MySQL8.0版本
1.2 设计工具:
Enterprise Architect
1.3连接工具:
Navicat、服务器为1核(vCPU) 2 GiB
在线商城首页
商城官网
我的购物车
我的订单
登录/注册
{{ user.nickname }}
个人信息
退出
搜索
- 手机
- 电脑
- 家装
- 医药
- 女装
- 男装
- 美妆
- 食品
{{item.refer}}
{{item.name}}
¥{{item.price}}
可以勾选商品进行计算价格,然后进行商品结算 去订单页面付款,也可以选择删除购物车里面的商品。
可以查看自己的订单的商品,设置5s时间自动关闭。支付使用支付宝沙箱支付,对于已经支付的订单无法二次支付,即使支付也会报错,对于已支付的订单也不能进行取消。
支付宝进行回调信息存储到数据库,后台可以接收信息。
进行支付之后,后台可以对订单进行发货,用户在我的订单里面也可以看见订单状态是否发货,从而进行收货操作。
保 存
定位
返回主页
此功能可以参考我的另外一篇文章:(2条消息) SpringBoot实现简易聊天室_慕言要努力的博客-CSDN博客
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Constants;
import com.example.demo.common.Result;
import com.example.demo.controller.dto.UserDTO;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import com.example.demo.utils.TokenUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
private IUserService userService;
@PostMapping("/login")
public Result login(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400,"参数错误");
}
UserDTO dto = userService.login(userDTO);
return Result.success(dto);
}
@PostMapping("/register")
public Result register(@RequestBody UserDTO userDTO) {
String username = userDTO.getUsername();
String password = userDTO.getPassword();
if (StrUtil.isBlank(username) || StrUtil.isBlank(password)) {
return Result.error(Constants.CODE_400,"参数错误");
}
return Result.success(userService.register(userDTO));
}
//新增或者更新
@PostMapping
public Result save(@RequestBody User user) {
return Result.success(userService.saveOrUpdate(user));
}
//删除
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
return Result.success(userService.removeById(id));
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List ids) {//批量删除
return Result.success(userService.removeByIds(ids));
}
// //查询所有数据
// @GetMapping
// public Result findAll() {
// return Result.success(userService.list());
// }
//
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(userService.getById(id));
}
@GetMapping("/username/{username}")
public Result findOne(@PathVariable String username) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
return Result.success(userService.getOne(queryWrapper));
}
@GetMapping("/page")
public Result findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String username) {
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.orderByDesc("id");
if (!"".equals(username)) {
queryWrapper.like("username", username);
}
return Result.success(userService.page(new Page<>(pageNum, pageSize), queryWrapper));
}
}
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
@Component
public class TokenUtils {
private static IUserService staticUserService;
@Resource
private IUserService userService;
@PostConstruct
public void setUserService() {
staticUserService = userService;
}
/**
* 生成token
*
* @return
*/
public static String genToken(String userId, String sign) {
return JWT.create().withAudience(userId) // 将 user id 保存到 token 里面,作为载荷
.withExpiresAt(DateUtil.offsetHour(new Date(), 2)) // 2小时后token过期
.sign(Algorithm.HMAC256(sign)); // 以 password 作为 token 的密钥
}
/**
* 获取当前登录的用户信息
*
* @return user对象
*/
public static User getCurrentUser() {
try {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("token");
if (StrUtil.isNotBlank(token)) {
String userId = JWT.decode(token).getAudience().get(0);
return staticUserService.getById(Integer.valueOf(userId));
}
} catch (Exception e) {
return null;
}
return null;
}
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.demo.common.Result;
import com.example.demo.entity.Cart;
import com.example.demo.entity.User;
import com.example.demo.mapper.CartMapper;
import com.example.demo.service.ICartService;
import com.example.demo.utils.TokenUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@CrossOrigin
@RestController
@RequestMapping("/cart")
public class CartController {
@Resource
private ICartService cartService;
@Resource
private CartMapper cartMapper;
//新增或者更新
@PostMapping
public Result save(@RequestBody Cart cart) {
Integer userId = TokenUtils.getCurrentUser().getId();
//相同商品进行处理
Integer goodsId = cart.getGoodsId();
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("goods_id", goodsId);
queryWrapper.eq("user_id", userId);
Cart db = cartService.getOne(queryWrapper);
if (db != null) {
// db.setNumber(db.getNumber() + cart.getNumber());
db.setNumber(db.getNumber() + cart.getNumber());
cartService.updateById(db);
return Result.success();
}
//新增或更新
if (cart.getId() == null) {
cart.setUserId(userId);
}
cartService.saveOrUpdate(cart);
return Result.success();
}
@PostMapping("/number/{id}/{number}")
public Result updateNum(@PathVariable Integer id, @PathVariable Integer number) {
cartMapper.updateNum(number, id);
return Result.success();
}
//删除
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
return Result.success(cartService.removeById(id));
}
@PostMapping("/del/batch")
public Result deleteBatch(@RequestBody List ids) {//批量删除
return Result.success(cartService.removeByIds(ids));
}
//查询所有数据
@GetMapping
public Result findAll() {
return Result.success(cartService.list());
}
@GetMapping("/{id}")
public Result findOne(@PathVariable Integer id) {
return Result.success(cartService.getById(id));
}
// @GetMapping("/id/{id}")
// public Result findOne(@PathVariable String userId) {
// QueryWrapper queryWrapper = new QueryWrapper<>();
// queryWrapper.eq("userId", userId);
// return Result.success(cartService.getOne(queryWrapper));
// }
@GetMapping("/page")
public Result findPage(@RequestParam Integer pageNum,
@RequestParam Integer pageSize,
@RequestParam(defaultValue = "") String name) {
User currentUser = TokenUtils.getCurrentUser();
Integer userId = currentUser.getId();
String role = currentUser.getRole();
return Result.success(cartMapper.page(new Page<>(pageNum, pageSize), userId, role, name));
}
}
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.Quarter;
import com.example.demo.common.Result;
import com.example.demo.entity.User;
import com.example.demo.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/echarts")
public class EchartsController {
@Autowired
private IUserService userService;
@GetMapping("/example")
public Result get() {
Map map = new HashMap<>();
map.put("x", CollUtil.newArrayList("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"));
map.put("y", CollUtil.newArrayList(150, 230, 224, 218, 135, 147, 260));
return Result.success(map);
}
@GetMapping("/members")
public Result members() {
List list = userService.list();
int q1 = 0; //第一季度
int q2 = 0; //第二季度
int q3 = 0; //第三季度
int q4 = 0; //第四季度
for (User user : list) {
Date createTime = user.getCreateTime();
Quarter quarter = DateUtil.quarterEnum(createTime);
switch (quarter) {
case Q1: q1 += 1; break;
case Q2: q2 += 1; break;
case Q3: q3 += 1; break;
case Q4: q4 += 1; break;
default: break;
}
}
return Result.success(CollUtil.newArrayList(q1, q2, q3, q4));
}
}
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.example.demo.entity.Files;
import com.example.demo.entity.Goods;
import com.example.demo.mapper.FileMapper;
import com.example.demo.mapper.GoodsMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
@RestController
@RequestMapping("/file")
public class FileController {
@Value("${files.upload.path}")
private String fileUploadPath;
@Value("${server.ip}")
private String serverIp;
@Resource
private FileMapper fileMapper;
@Resource
private GoodsMapper goodsMapper;
@PostMapping("/upload")
public String upload(@RequestParam MultipartFile file) throws IOException {
String originalFilename = file.getOriginalFilename();
String type = FileUtil.extName(originalFilename);
long size = file.getSize();
//定义一个文件的唯一标识码
// String uuid = IdUtil.fastSimpleUUID();
// String fileUUID = uuid + StrUtil.DOT + type;
// File uploadFile = new File(fileUploadPath + fileUUID);
//先存储到磁盘
File parentFile = new File(fileUploadPath);
// File parentFile = uploadFile.getParentFile();
//判断目录是否存在,不存在就新建
if (!parentFile.exists()) {
parentFile.mkdirs();
}
String uuid = IdUtil.fastSimpleUUID();
String fileUUID = uuid + StrUtil.DOT + type;
File uploadFile = new File(fileUploadPath + fileUUID);
file.transferTo(uploadFile);
String url = "http://" + serverIp + ":9090/file/" + fileUUID;
//存储到数据库
Files saveFile = new Files();
Goods goods = new Goods();
saveFile.setName(originalFilename);
saveFile.setType(type);
saveFile.setSize(size/1024);
saveFile.setUrl(url);
goods.setUrl(url);
fileMapper.insert(saveFile);
goodsMapper.insert(goods);
return url;
// String md5 = SecureUtil.md5(file.getInputStream());
// Files files = getFileByMd5(md5);
//
// String url;
// if (files != null) {
// url = files.getUrl();
// } else {
// file.transferTo(uploadFile);
// url = "http://localhost:9090/file/" + fileUUID;
// }
// //存储到数据库
// Files saveFile = new Files();
// saveFile.setName(originalFilename);
// saveFile.setType(type);
// saveFile.setSize(size/1024);
// saveFile.setUrl(url);
// saveFile.setMd5(md5);
// fileMapper.insert(saveFile);
// return url;
}
@GetMapping("/{fileUUID}")
public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
// 根据文件的唯一标识码获取文件
File uploadFile = new File(fileUploadPath + fileUUID);
// 设置输出流的格式
ServletOutputStream os = response.getOutputStream();
response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileUUID, "UTF-8"));
response.setContentType("application/octet-stream");
// 读取文件的字节流
os.write(FileUtil.readBytes(uploadFile));
os.flush();
os.close();
}
/**
* 通过文件的md5查询文件
* @param md5
* @return
*/
private Files getFileByMd5(String md5) {
// 查询文件的md5是否存在
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.eq("md5", md5);
List filesList = fileMapper.selectList(queryWrapper);
return filesList.size() == 0 ? null : filesList.get(0);
}
}
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.example.demo.mapper")
public class MybatisPlusConfig {
/**
* 分页插件
*/
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
public interface Constants {
String CODE_200 = "200"; //成功
String CODE_400 = "400"; //参数不足
String CODE_401 = "401"; //权限不足
String CODE_500 = "500"; //系统错误
String CODE_600 = "600"; //其他业务异常
}
完结撒花,对于在线商城这个项目呢,肯定还会有很多的优化,这个项目我也有2个版本,就是服务器上面的和不是服务器上面的,但是基本上都差不多。基本功能呢也都能实现, 只是跟商业的比起来肯定差点意思啦。各位小伙伴觉得笔者写的还不错,就多多点赞,需要源码的也可以私信我哦,看见信息第一时间回复大家。记得点赞关注!!!!