基于SpringBoot+Vue的二手车交易系统的设计与实现
该项目适用于各种电子商城项目,有需要源码请私信或者留言
项目介绍
该二手车交易系统网站的开发是基于开源环境JDK1.8,采用IDEA作为系统的开发环境,SpringBoot作为底层框架,运用Redis服务器作为基础服务器技术,MySQL数据库技术作为底层基础数据库,vue作为全家桶技术作为基础前端开发,运用服务处理层、业务信息处理层等技术层和大数据服务处理层等技术三层架构技术来协助进行整个系统结构模型的完整的搭建。本开发模式系统实现中所采用到的采用了这样一个数据库前后端接口进行分离后渲染的数据库开发模式,在系统运行于该数据库开发的模式条件下,前端数据开发维护人员则只须在需要下先通过调用一个由系统后端程序所能够提供出来的数据库接口以直接获取到相关的数据,然后再在其中对数据前端进行后渲染等操作实现即可,后端程序员们则是仅据需要而在中给相关数据前端直接提供一个数据库接口,连接到相关数据库。
项目需求分析
二手车交易系统的设计目标是:开发一个专门为二手车买卖服务的简单易用的商品网站。新用户可以注册一个账号,注册完成后可登录该网站,登录成功后进入到二手车交易系统网站的首页,首页会展示出大量正在出售的二手车,任用户选择浏览,用户选择某个车辆,点击进入详情页面,会详细介绍该车辆的所有信息,让用户清楚车辆状况,用户买的放心,用户需要下订单,可通过支付宝支付的方式向商家付款买下车辆,用户购买完商品之后,可以在该网站上查看订单的支付情况。据了解到,目前有很多网上交易平台,比如拼多多、淘宝、京东等,做得这个二手车交易系统网站应该有以下的基本功能。
技术栈
该项目采用了前后端分离的开发模式,相比于传统的开发,该模式有很多的优点如下。
(1)可以减低代码的耦合度。
(2)发现问题能够精准定位,前端的问题前端解决,后端的问题后端解决。
(3)减少后端服务器的开发/负载压力
(4)代码管理方便,可以说前后端是两个项目,项目文件结构清晰,两个项目的代码互不影响。
(5)页面显示再多的东西也不担心,因为是异步加载
(6)增加代码的易读性和维护性
(7)支持前后端并行开发,提高前端开发设计效率,节省设计开发的时间。
后端技术栈
前端技术栈
开发环境
开发工具
系统的总体架构
系统采用的SpringBoot框架进行开发,对于Spring Boot框架分层设计解析如下。
model层
model对象层即数据库实体模型对象层,也有常常会被某些人误称为entity对象层,pojo(Plain Ordinary Java Object,即简单普通的Java对象)层。
dto英文的全称缩写为:Data Transfer Object,即进行数据的直接传输运算的对象。它又被人们通常用之于仅是指能够将一个用户系统所需进行处理操作的数据直接的传送到数据层结构中的任意一个外围。例如,当客户需要查询某一组至少具有大约50个字段信息定义的数据表时,接口或一些其他的服务通常可能只可能会根据需要选择使用在这表其中包含的或其中的一些字段,dto表实际上可能是数据包装或传送中的最后一个对象。它有些甚至是可以是专门设计用来隐藏数据层字段信息的定义,提高整个系统性能,减少了对一些不存在和必要存在的字段信息产生的数据传输上的损耗。
本二手车交易系统的数据库实体层的实体类分别有地址实体类、购物车实体类、分类实体类、订单实体类、商品实体类、轮播图实体类、用户实体类。
dao层
dao层也即数据库是一种数据持久层,也即常常会被人们泛称为数据库mapper层。dao层的主要功能的数据库业务作用主要表现在为客户访问数据库,向指定数据库对象自动发送sql语句,完成其对数据文件进行的数据自动查询增删操作及数据库改错等查检任务。本应用接口系统接口中使用的数据库mapper层数据库接口中所要存放运行着数据的数据库接口是应用接口系统的(interface)管理接口,分别被设计的有地址信息查询管理接口、分类管理信息接口、购物车查询管理信息接口、商品分类查询信息管理接口、轮播图查询管理信息接口、订单处理跟踪查询接口、用户信息管理查询接口,这些信息管理的接口也就可供通过接口对数据库的本身功能直接的调用并进行管理操作,服务层需要用到哪个接口可直接调用该接口就可以。
service层
service层也即是业务逻辑层,service逻辑层是负责调用dao逻辑层上的业务接口,接收从dao逻辑层接口中所返回而来的各种业务数据,完成项目系统中业务的所有业务基本业务逻辑功能设计。本单机系统使用的在service层结构下的接口每个接口文件夹中一般都只可以定义由其中一个接口文件类和由另一个接口类文件所定义组成,接口通过定义实现使用接口方法,类则通过定义调用的接口文件类实现使用接口方法具体的操作,比如在service层结构中定义的在一个RegLogin文件类中定义调用的接口文件类(RegLogService)就定位类似于了User geTUserByName(String email) tHrows IOException;User getUserByUserName(String username) tHrows IOException;Void insertUser(String userid, String name, String email, String pwd,String phone, String status,String date,String prikey) throws IOException;三个方法,在RegLogServiceImp类中可调用这个三个方法,在RegLogServiceImp类中需要调用dao层的用户接口即private RegLogUser regLogUsermapper;这样regLogUsermapper对象就有了接口中的所有方法,可直接调用。
controller层
controller层即控制层,controller控制层提供的重要功能主要为请求响应和响应时间控制,负责与前后务端进行交互,接受前端发送请求,调用到service控制层,接收从service控制层中返回客户端的请求数据,最后再返回到具体应用的请求页面和返回数据传送到客户端。
用户功能模块
注册模块
初次使用该系统的用户,可以在本系统中注册一个属于自己的账号,且保证用户名不可与系统中已存在的用户名重复,用户在注册页面只需要输入用户名、密码、手机号、邮箱即可完成注册。
用户输入正确的信息后就可以进行注册了,点击注册,前端调用后端接口“http://localhost:8080/login/getRegister”将数据返回给后端,然后后端再对数据进行处理,将用户在前端注册页面输入的信息通过该接口传递给后端,后端并保存到数据库的用户表中,用户在注册页面成功之后,用户就可以通过用户名进行登录了。
//注册功能
@RequestMapping("/getRegister")
public RegResult Register(@RequestParam("username") String username,
@RequestParam("email") String email,
@RequestParam("password") String password,
@RequestParam("phone") String phone) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
RegResult result = new RegResult();
System.out.println(username.length());
if(username.equals("") || email.equals("") || password.equals("") || phone.equals("")){
result.setStatus(404);
result.setMsg("填写信息不全");
return result;
}
User user = regLogServiceImp.getUserByName(username);
if (user != null) {
result.setStatus(2002);
result.setMsg("账号已存在,注册失败!");
}
else {
String userid = UUID.randomUUID().toString();
Map<String, String> keyMap = RSAUtils.createKeys(512);
String publicKey = keyMap.get("publicKey");
String privateKey = keyMap.get("privateKey");
//公钥加密
String encodedData=RSAUtils.publicEncrypt(password,RSAUtils.getPublicKey(publicKey));
String date = DateUtil.ptfDate();
regLogServiceImp.insertUser(userid,username,email,encodedData,phone,"可用",date,privateKey);
result.setStatus(200);
result.setMsg("注册成功!");
}
return result;
}
登录模块
用户以游客的身份浏览是没有权限对商品进行购买的,系统没有检测到token值,是没有权限点击购买、购物车、我的订单的,必须登录之后才可以进行这一系列操作。
//登录验证
@RequestMapping("/UserLogin")
public LoginResult Login(@RequestParam("username") String username,
@RequestParam("password") String password) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException {
User user = regLogServiceImp.getUserByUserName(username);
LoginResult result = new LoginResult();
LoginData loginData = new LoginData();
if(user==null){
result.setMsg("无此用户,请重新输入正确用户名");
result.setStatus(2008);
}
else {
if(RSAUtils.privateDecrypt(user.getPwd(), RSAUtils.getPrivateKey(user.getPrivatekey().trim())).equals(password)){
result.setStatus(0);
String token = TokenUtil.token(user.getUserid().trim());
loginData.setToken(token);
result.setMsg("登录成功");
result.setData(loginData);
}
else {
result.setStatus(2007);
result.setMsg("密码错误");
}
}
return result;
}
首页商品展示模块
首页的商品是通过分类进行查询之后展示,本系统的首页展示的是五菱汽车和奥迪这两大分类的车辆信息,每一个商品都是一个小矩形框,展示的信息主要是车辆的名称、介绍、价格、图片,首页商品展示每个分类的商品最多展示10个商品。
数据库定义了首页商品展示每个分类的商品最多展示10个商品@Select(“select-good_id,price,oldprice,name,imageFoot,subtitle,image,pushtime”+“from goods where category_id = #{category_id} limit 10”),"http://localhost:8080/index/productfootnormal"是前端获取商品信息的接口,后端提供的接口代码如下。
@RequestMapping("/productfootnormal")
public ProductFootResult getProductFootNormal(@RequestParam("categoryId") int categoryId) throws IOException {
ProductFootResult productFootResult = new ProductFootResult();
productFootResult.setStatus(0);
List<ProductFootInfo>productFootInfo=productFootImp.getProductFootInfoNormal(categoryId);
productFootResult.setData(productFootInfo);
return productFootResult;
}
数据库通过分类的id进行查找商品的价格、介绍、图片、年份、商品id、名称等。代码如下。
@Select("select good_id,price,oldprice,name,imageFoot,subtitle,image,pushtime" +
" from goods where category_id = #{category_id} limit 10")
List<ProductFootInfo> getProductFootInfoNormal(int category_id);
商品详情模块
商品详情页的作用主要是为了用户更好的了解商品的信息,这里的信息比首页提供的信息要更加详细。提供一张参数表,将车辆的所有信息都填入这张表内,参数表主要展示生产厂家、发动机、变速箱、车身结构、车型、年份。前端通过调用“http://localhost:8080/product/getinfo”接口获取带商品的信息,然后对数据进行渲染。
为了用户拥有更好的体验在商品详情页中用户可以放大图片观察更仔细,vue提供了这么一个插件–pic-zoom,这里将图片放大三倍,使用方法页非常的简单,用户只需要将鼠标移动到图片即可自动放大。
商品详情调用的后端接口代码
@CrossOrigin
@RestController
@RequestMapping("product")
public class ProductController {
@Autowired
private ProdServiceImp prodServiceImp;
@RequestMapping("getinfo")
public ProductResult getProductInfo(@RequestParam("id") int id) throws IOException {
ProductResult productResult = new ProductResult();
productResult.setStatus(0);
productResult.setData(prodServiceImp.getProductInfo(id));
return productResult;
}
购物车功能模块
在商品详情页中有添加到购物车按钮和立即购物买按钮都是跳转到购物车的,因为用户可以以游客的身份进行商品浏览,所以在跳转到购物车时需要判断用户是否登录,即有没有token值,如果系统中没有查询到对应的token值,那么说明用户处于未登录状态,没有权限进入购物车,需提醒用户进行登录后再进行购买。对token的判断,boolean success = TokenUtil.verify(pushcart.getToken());将token定义为一个布尔类型,对其进行判断如果success为true,那么说明用户已登录,可调用getUserByUserName、getGoodByid、getGoodByidinsert、insCartGood、updateCartGood、getCartProduct等方法,如果 success为false,那么cartResult.setStatus(10);设置为未登录状态。
添加购物车接口是"http://localhost:8080/carts/push",添加购物车成功之后,用户可以对购物车内的商品进行相应的操作,比如说可以对商品的数量进行操作,http://localhost:8080/carts/updatecart
接口被调用,该接口是更新购物车的,具体的实现:对商品数量进行增加减少操作。用户可以删除不想买购物的商品,调用的接口是http://localhost:8080/carts/del
,该接口后端对数据库的处理为@Delete(“delete from cart where user_id like #{userid} and good_id = #{id}”),更cart表的信息;可以选择全选将购物车内所有的商品进行下单,调用接口"http://localhost:8080/carts/selectAll",购物车内的商品全部处于选中状态,MySQL数据库语句为@Update(“update cart set productSelected = true where user_id like #{userid}”)。
用户勾选购物车内的商品后,计算总价完成,就可以点击“去结算”按钮,进入到订单页面。
对于token的判断代码如下
boolean success = TokenUtil.verify(pushcart.getToken());
if (success) {
cartResult.setStatus(0);
User user=regLogServiceImp.getUserByUserName(pushcart.getUsername().trim());
String userid = user.getUserid();
CartGood cartGood = goodServiceImp.getGoodByid(userid, pushcart.getProductId());
if (cartGood == null) {
int goodcount = 1;
CartGoodInsert goodByidinsert = goodServiceImp.getGoodByidinsert(pushcart.getProductId()); goodServiceImp.insCartGood(userid,pushcart.getProductId(),goodByidinsert.getName(),goodByidinsert.getPrice(), goodcount, goodByidinsert.getSubtitle(), goodByidinsert.getProductStock(),
goodByidinsert.getStatus(), true);
} else {
goodServiceImp.updateCartGood(userid, cartGood.getCount() + 1, pushcart.getProductId(), (cartGood.getCount() + 1) * cartGood.getPrice());
}
cartProductVoList cartProductVoList = cartServiceImp.getCartProduct(userid);
int cartTotalPrice = 0;
boolean selectedAll = true;
int cartTotalQuantity = 0;
for (cartProduct cartProduct : cartProductVoList.getList()) {
cartTotalPrice += cartProduct.getProductTotalPrice();
if (!cartProduct.isProductSelected()) {
selectedAll = false;
}
cartTotalQuantity += cartProduct.getCount();
}
cartResult.setStatus(0);
cartResult.setCartTotalPrice(cartTotalPrice);
cartResult.setCartTotalQuantity(cartTotalQuantity);
cartResult.setData(cartProductVoList);
cartResult.setImageHost("www.mi.com");
cartResult.setSelectedAll(selectedAll);
} else {
cartResult.setStatus(10);
}
收货地址模块
在订单付款之前必须要填写收货地址,收货地址需要填写收件人,号码,省份,城市,具体地址,编号,每个用户都可以拥有多个收货地址,用户也可对已保存的收货地址进行修改,也可删除不想要的收货地址。新建收货地址调用的接口是’http://localhost:8080/shippings/push’,数据库对address表添加数据。http://localhost:8080/shippings/${checkedItem.id}
为修改收货地址和删除收货地址的接口,虽然两个都请求同一个接口,但是由于${checkedItem.id}参数不同,请求方式不同,修改地址接口的请求方式是POST请求,而删除地址接口的请求方式是delete请求。
新建收货地址
收货地址
订单支付模块
订单确认页面除了展示收货地址之外,还需要展示这一批订单内所有的商品信息,统计商品件数,计算订单总价,就可以直接去结算了,点击“去结算”按钮,调用的接口是’http://localhost:8080/orders/createorder’,跳转到订单支付页面,订单支付需要展示订单详情,包括订单号、收件地址等,支付方式统一使用支付宝支付。
沙箱环境 (Beta) 是支付宝开放平台为开发者提供的与线上环境完全隔离的联调测试环境,在沙箱环境中完成的调用不会对线上数据造成任何影响,尤其适合涉及资金链路的能力的调试。我们只需要通过自己的支付宝注册一个沙箱环境的账号就可以对其进行使用了。
orders/createorder接口代码如下
@PostMapping("/createorder")
public OrderResult createOrder(@RequestBody OrdCreaParm ordCreaParm) throws Exception {
OrderResult orderResult = new OrderResult();
orderResult.setStatus(0);
OrderList orderList = orderServiceImp.creatOrder(ordCreaParm);
if(orderList.getOrderNo() == 0){
orderResult.setStatus(1);
return orderResult;
}
orderResult.setData(orderList);
return orderResult;
}
我的订单模块
我的订单也是具有权限的,即要求用户必须登录之后才可以查看“我的订单”,也就是说系统没有检测到token值,是不会给予用户查看“我的订单”的。
我的订单是用户支付完成之后生成的一个订单列表,可以通过订单列表查看到每笔订单的支付情况,分别有两种情况,一种是支付成功,另一种是未支付,用户通过支付宝支付相应的金额后订单的状态就会变为支付成功,如果用户只是下订单但是还未登录支付宝支付,那么订单的状态是未支付状态。前端请求后端接口是"http://localhost:8080/orders/getorderlist",主要功能就是获取到订单信息,监听订单状态。在订单列表中展示了订单号、收件人、支付方式、支付时间、支付金额等信息,用户可以清楚的了解到每一笔订单详情。
我的订单调用接口代码
@RequestMapping("/getorderlist")
public UserOrdListResult getUserOrdList(String username) throws IOException {
UserOrdListResult userOrdListResult = new UserOrdListResult();
User user = regLogServiceImp.getUserByUserName(username);
String userid = user.getUserid();
List<UserOrdList> orderList = orderServiceImp.getOrderList(userid);
for(UserOrdList userOrdList:orderList){
int orderNo = userOrdList.getOrderNo();
List<UserOrdItemList> orderListItems = orderServiceImp.getOrderListItems(orderNo);
userOrdList.setItems(orderListItems);}
userOrdListResult.setStatus(0);
userOrdListResult.setTotal(orderList.size());
userOrdListResult.setList(orderList);
return userOrdListResult;
}
商品分类功能模块
商品分类是通过商品的分类id进行分类的,目前本系统中有九大分类,分别是五菱、长城、奔驰、宝马、奥迪、大众、别克、东风日产、本田,一个分类都是对应的厂家产品,做商品分类主要的目的就是用户可以通过点击不同的分类快速查询到自己想要了解的品牌产品。通过调用"http://localhost:8080/index/category"该接口获取到分类的名称,再通过路由跳转到具体的分类页面,this.$router.push({path: “/goodsByCategory”,query: { id: categoryId },});路由跳转时需要携带分类的id,这样才能准确的跳转到对应的页面。通过id跳转到分类页面之后需要调用接口获取该分类的所有商品信息,调用的接口是"http://localhost:8080/goods/ByCategory_id"-@Select(“select-name,price,oldPrice,sellcount,icon,image,category_id,good_id,subtitle,pushtime from goods where category_id = #{category_id}”)为该接口对数据库进行的操作,通过分类id查询goods表获取分类商品的信息。
获取分类商品信息的接口代码
@RequestMapping("ByCategory_id")
private List<Good> ByCategoryId(@RequestParam("category_id") int category_id) throws IOException {
return goodServiceImp.getGood(category_id);
}
获取到分类名称的接口代码
@RequestMapping("/category")
public CategoryResult getCategory() throws IOException {
CategoryResult categoryResult = new CategoryResult();
categoryResult.setStatus(0);
categoryResult = categoryIndexImp.getCategoryGoods();
return categoryResult;
}
管理员功能模块
用户管理模块
管理员用户可以管理用户,所有的用户信息都罗列在列表中,管理员可以对其进行修改和删除操作,因为后端设置用户密码时使用了RSA加密技术,所以即使是管理员也是无权查看用户的密码的,管理员可以查看的信息有用户名、邮箱、号码、注册时间等。前端通过调用 'http://localhost:8081/User/getUsers’接口获取到用户的信息。
用户管理代码
@CrossOrigin
@RestController
@RequestMapping("User")
public class UserController {
@Autowired
private UserServiceImp userServiceImp;
@RequestMapping("/getUsers")
public UserResult getUsers() throws IOException {
UserResult userResult = userServiceImp.getUsers();
return userResult;
}
}
商品上下架模块
管理员既可以自动对某些商品自动进行上架等操作,也同时可以自己在系统内存中任意删除掉某一个上架商品,还同时可以手动对其它已成功上架了的商品信息进行自动编辑,修改该商品上的所有信息,上架商品需要填写商品的名称、分类id、售价、年份、车型、图片等信息,添加成功的商品会在具体的分类中查询到。系统中所有的商品已列表的形式展示给管理员,方便管理员对其进行操作,调用’http://localhost:8081/Good/getGood’接口获取到系统中所有的数据,然后通过分类类别进行分类展示到列表中。列表中操作一列使用到了vue中的作用域插槽技术, slot-scope=“scope”,通过scope就可以获取到当前行的信息,“操作”列具体就两个操作,一个是编辑操作,一个是删除操作,编辑操作就是修改数据信息,然后保存到数据库中调用的接口是’http://localhost:8081/Good/updGood’,对goods表进行数据更新;删除操作是将该商品在数据库中删除掉,调用的接口是’http://localhost:8081/Good/delGood’,对goods表进行删除操作。
获取商品信息接口代码
@GetMapping("/getGood")
private GoodResult getGood(@RequestParam("pageIndex") int pageIndex,
@RequestParam("pageSize") int pageSize,
@RequestParam("name") String goodname,
@RequestParam("price") int price,
@RequestParam("price") String subtitle
) throws IOException {
GoodResult goodResult=goodServiceImp.getGood(pageIndex,pageSize,goodname,price,subtitle);
return goodResult;
}
编辑调用接口代码
@RequestMapping("/updGood")
private GoodResult getGoodByName(@RequestParam("good_id") int goodid,
@RequestParam("name") String goodname,
@RequestParam("newhot") int newhot,
@RequestParam("image") String image,
@RequestParam("price") int price,
@RequestParam("subtitle") String subtitle,
@RequestParam("pushtime") String pushtime) throws IOException {
GoodResult goodResult = goodServiceImp.updGood(goodid,goodname,newhot,image,price,subtitle,pushtime);
return goodResult;
}
删除调用的接口
@PostMapping("/delGood")
private void delGood(@RequestBody good good) throws IOException {
goodServiceImp.delGood(good);
}
商品分类模块
管理员可以对商品分类的类名进行修改操作
订单管理模块
订单管理列表展示了系统中所有订单的具体信息,方便管理员对其进行管理,列表展示的信息具体为订单号、价格、收件人、联系方式、省份、城市、地址、邮政编码等信息。调用的接口是’http://localhost:8081/order/orderList’,对数据库中的订单表进行查询,查询到的数据通过后端接口传递给前端。
订单管理代码
@CrossOrigin
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private orderServiceImpl orderService;
@GetMapping("/orderList")
public List<Order> getOrderList() throws IOException {
List<com.zty.xiaomiadmin.server.Entity.Order.Order> list = orderService.getOrderList();
return list;
}
}
总结
这个二手车交易系统网站其实也就是一个类似于电子商务平台的网站模式来的进行了设计,这个系统网站最主要的功能其实就是一个新注册用户先能够通过注册登录,然后用户能够登录浏览二手车商品的所有页面,用户成功登录浏览过后便可以成功下单和购买该商品,通过使用支付宝进行支付并完成所有订单进行支付,管理员用户便可以完成管理注册用户,管理该商品,管理订单。
该开发系统主要采用的框架是一种前后端代码分离式开发的模式,在使用这种框架模式前提下就大大的降低了两个项目代码管理的工作耦合度,前端也就是只需管理好前端代码,后端项目只须管理好后端代码,分工比较明确,代码干净整洁,代码可读性更强。后端采用的是Java的SpringBoot框架,我们的课程中是有Java课程的,虽然没有学过SpringBoot框架,但是有Java基础,学习SpringBoot框架也是相对轻松的,SpringBoot框架比原生的Java开发更加简便,代码量更加少,更适合项目开发。我们学习的SQLserver数据库,项目中用到的是MySQL数据库,两者使用的方法大同小异,使用起来也没有什么阻碍。前端用当前国内最流行的前端框架Vue.js,Vue上手容易,操作简单,Vue采用的是MVVM模式进行开发,可实现数据双向绑定,前端UI则用使用了饿了么提供Element-UI框架,很多样式、组件都替我们封装好了,可直接使用即可,极大程度的节省了开发时间。