校园二手商品在线交易网站的设计与实现简单总结

1.项目架构

Spring Boot + Thymeleaf + Mybatis

2.功能模块

(1)前台功能模块

  • 用户模块:注册(上传头像)、登录(后可以实时显示出用户上传的头像)、更新个人信息、退出登录
  • 商品模块:商品首页、分类分页查看商品、查看商品的详情、模糊搜索商品、发布二手商品(上传商品的图片)并删除
  • 购物车模块:购物车中添加商品、查看购物车(可以显示出购物车中的商品数量)、删除购物车中的某件商品
  • 地址模块:添加地址、删除地址、查询地址、修改地址
  • 订单模块:下单(增加订单、增加订单详情)、查询订单(卖出订单+购买订单)、订单发货收货、取消订单
  • 支付模块:使用支付宝沙箱环境进行支付
  • 收藏模块:添加收藏、查看收藏、删除收藏
  • 留言模块:添加留言、查询留言

(2)后台功能模块

主要实现用户模块、商品模块、订单模块、分类模块、系统管理。

  • 用户模块:分页查看所有用户(可以设置每页显示条数)(显示的用户按照注册时间降序排列)、按照用户的用户名或者学校对用户进行模糊搜索、单选或多选删除用户、修改某个用户的信息。
  • 商品模块:分页查看所有发布的商品(可以设置每页显示条数)(显示的商品按照注册时间降序排列)、按照商品名称或者商品分类对商品进行模糊搜索、单选或多选删除商品(管理员删除是将商品的状态修改为3表示删除)、修改某个商品的信息。
  • 订单模块:分页查看所有的订单(可以设置每页显示条数)(显示的订单按照下单时间降序排列)、按照订单编号对订单进行搜索、单选或多选删除订单信息、修改某个订单的信息、查看某个订单的详情。
  • 分类模块:对已有商品分类进行修改、添加新的商品分类。
  • 系统管理:登录、对个人的基本信息(登录名称和邮箱)进行修改。对密码进行修改。安全退出。

3.实现业务逻辑:

4.自定义拦截器

4.1.实现HandlerInterceotor接口

(1)preHandler(),return 的是boolean,true时,不拦截请求;false时,拦截请求。请求前执行。

(2)postHandler()请求后执行。

(3)afterCompletion()响应页面渲染后执行。

4.2.注册拦截器

自定义类:

(1)实现WebMvcConfigurer接口

(2)加上注解,@SpringBootConfiguration//Spring Boot的配置类,标注在某个类上,表示这是一个Spring Boot的配置类

(3)在addInterceptors(InterceptorRegistry registry)方法中注册拦截器,方法中通过registry.addInterceptor(portalLoginCheckInterceptor)//括号中的是拦截器

.addPathPatterns("/portal/user/**")//添加需要拦截的路径

.excludePathPatterns(excludeUrl);//排除不需要拦截的路径

注意:如果注册了多个拦截器,则按照拦截器的顺序执行,先注册的先执行

5.连接支付宝网站支付的沙箱环境

5.1.在pom.xml文件中添加依赖

5.2.创建AlipayConfig.java文件

5.3.把demo中alipay.trade.page.pay.jsp改成controller控制层代码

支付接口调用流程

调用顺序如下:

  1. 商户系统请求支付宝接口alipay.trade.page.pay,支付宝对商户请求参数进行校验,而后重新定向至用户登录页面。
  2. 用户确认支付后,支付宝通过get请求returnUrl(商户入参传入),返回同步返回参数。
  3. 交易成功后,支付宝通过post请求notifyUrl(商户入参传入),返回异步通知参数。

若由于网络等问题异步通知没有到达,商户可自行调用交易查询接口alipay.trade.query进行查询,根据查询接口获取交易以及支付信息(商户也可以直接调用查询接口,不需要依赖异步通知)。

 

6.图片上传

页面的三个条件:

(1)必须指定method属性为post

(2)必须指定enctype属性为multipart/form-data

(3)使用类型为file的<input>标签,供用户选择文件

在业务方法中添加MultipartFile类型的形参,调用transferTo()方法,并生成唯一的文件名。

//获取原始文件名

String originalFilename = file.getOriginalFilename(); // xxx.png

//获取扩展名

String extend = originalFilename.substring(originalFilename.lastIndexOf("."));

//重新生成唯一的文件名

String newName = UUID.randomUUID().toString();

File file1 = new File(uploadPath,newName + extend);

try {

file.transferTo(file1);//保存文件

    user.setPhoto(newName + extend);

} catch (IOException e) {

    e.printStackTrace();

}

静态资源的设置:

一、spring boot项目中上传图片到本项目的路径下,需要重启项目才能显示图片解决方法

(1)application-dev.yml文件中设置上传文件的路径

(2)在controller层,获取在yml文件中的路径

(3)在新建的配置文件中映射图片的静态路径

addResourceHandler()里配置需要映射的文件夹,此处代表映射文件夹img/commodity下的所有资源。

addResourceLocations()配置文件夹在系统中的路径,使用绝对路径,格式为“file:你的路径”

二、spring boot项目部署到阿里云服务器上显示上传图片

(1)application-prod.yml文件中设置上传文件的路径

上传的文件的路径写的是绝对路径,在Linux环境下,要创建出对应的目录

(2)在controller层,获取在yml文件中的路径(同上)

(3)在新建的配置文件中映射图片的静态路径(同上不需要修改)

7.Springboot中PageHelper分页查询使用方法(mybatis+thymeleaf)

一:导入依赖

<dependency>

    <groupId>com.github.pagehelper</groupId>

    <artifactId>pagehelper-spring-boot-starter</artifactId>

    <version>1.2.13</version>

</dependency>

二:配置yml文件中PageHelper的属性

pagehelper:                #分页插件

  helper-dialect: mysql

  reasonable: true

  support-methods-arguments: true

  params:

三:在controller类中使用

1.在查询方法上调用PageHelper.startPage()方法,设置分页的页数和每页信息数,

2.将查询出来的结果集用PageInfo的构造函数初始化为一个分页结果对象

3.将分页结果对象存入model,返回前端页面

四:前端展示分页主要是thymeleaf的使用。

8.如何实现下单?

如何进行一些批量操作:

<delete id="deleteByIds" parameterType="list">

delete from collect

where collectionid in

<foreach collection="idList" item="collectionid" open="(" close=")" separator=",">

#{collectionid}

</foreach>

</delete>

9.地址的三级联动?

实现思路:

1.创建省市县三级地址,分别采用下列方式表示

省份:使用一维数组

城市:使用二维数组,和一维数组省份对应

区/县:使用三维数组,和二维数组城市对应

2.创建HTML文件,然后创建三个select选择框,分别代表省市县

3.创建实现联动的js文件,然后按照下面步骤实现

(1)获取三个select对象

  • 设置省份

遍历省份数组

创建option对象

将option对象加追加到select中

  • 设置城市

获取已经选择的省份下标

根据省份下标遍历城市数组

创建option对象

将option对象加追加到select中

  • 设置县区

获取已经选择的省份和城市下标

根据省份和城市下标遍历区县数组

创建option对象

将option对象加追加到select中

4.网页加载完成应该将省市县显示在第一个

当省份改变城市的区县一起改变

当城市改变区县改变

三级联动的js实现:

// 当框框加载完成之后调用设置省份
window.onload = setProvince;

// 获取省市县/区的select选择框对象
var province = document.getElementsByTagName("select")[0];
var city = document.getElementsByTagName("select")[1];
var county = document.getElementsByTagName("select")[2];

// 设置省份
function setProvince() {
    // 遍历省份数组, provinceArr在city.js中
    for (var i = 0; i < provinceArr.length; i++){
        // 创建省份option选项
        var opt = document.createElement("option");
        opt.value = provinceArr[i];         // 设置value-提交给服务器用
        opt.innerHTML = provinceArr[i];     // 设置option文本显示内容
        province.appendChild(opt);          // 追加省份到下拉框

        // 当省份发生变化更改城市
        province.onchange = function(){
            setCity(this.selectedIndex);
        };
    }

    // 省份加载完成,默认显示第一个省份的城市
    setCity(0);
}

// 设置城市
function setCity(provincePos) {
    // 获取省份对象的城市,cityArr在city.js中
    var citys = cityArr[provincePos];
    city.length = 0;                  // 清空长度,重新从0开始赋值下拉框

    for (var i = 0; i < citys.length; i++){
        // 创建城市option选项
        var opt = document.createElement("option");
        opt.value = citys[i];         // 设置value-提交给服务器用
        opt.innerHTML = citys[i];     // 设置option文本显示内容

        city.appendChild(opt);
        city.onchange = function() {
            setCounty(provincePos, this.selectedIndex);
        }
    }

    // 默认显示城市的第一个县/区
    setCounty(provincePos, 0);
}

// 设置县/区, 县/区是三位数组,需要传入哪个省份和城市
function setCounty(provincePos, cityPos) {
    // 获取县/区,countyArr在city.js中国
    var countys = countyArr[provincePos][cityPos];
    county.length = 0;

    for (var i = 0; i < countys.length; i++){
        // 创建县/区option选项
        var opt = document.createElement("option");
        opt.value = countys[i];         // 设置value-提交给服务器用
        opt.innerHTML = countys[i];     // 设置option文本显示内容
        county.appendChild(opt);        // 追加到县/区选择框中
    }
}

数据回响实现联动:

/*
* 获取某个元素下标
* arr: 传入的数组
* obj: 需要获取下标的元素
* */
function getArrayIndex(arr, obj) {
    var i = arr.length;
    while (i--) {
        if (arr[i] === obj) {
            return i;
        }
    }
    return -1;
}

// 设置城市
function getCity(provincePos, receiverCity) {
    // 获取省份对象的城市,cityArr在city.js中
    var citys = cityArr[provincePos];
    city.length = 0;                  // 清空长度,重新从0开始赋值下拉框

    for (var i = 0; i < citys.length; i++){
        // 创建城市option选项
        var opt = document.createElement("option");
        opt.value = citys[i];         // 设置value-提交给服务器用
        opt.innerHTML = citys[i];     // 设置option文本显示内容
        if (opt.value == receiverCity){
            opt.selected = true;      // 让回响的数据设置为选中
        }

        city.appendChild(opt);
        city.onchange = function() {
            setCounty(provincePos, this.selectedIndex);
        }
    }

    // 默认显示城市的第一个县/区
    setCounty(provincePos, 0);
}

// 设置县/区, 县/区是三位数组,需要传入哪个省份和城市
function getCounty(provincePos, cityPos, receiverDistrict) {
    // 获取县/区,countyArr在city.js中国
    var countys = countyArr[provincePos][cityPos];
    county.length = 0;

    for (var i = 0; i < countys.length; i++){
        // 创建县/区option选项
        var opt = document.createElement("option");
        opt.value = countys[i];         // 设置value-提交给服务器用
        opt.innerHTML = countys[i];     // 设置option文本显示内容
        if (opt.value == receiverDistrict){
            opt.selected = true;      // 让回响的数据设置为选中
        }
        county.appendChild(opt);        // 追加到县/区选择框中
    }
}

10.后台登录时验证码的实现?

运用Google的Kaptcha

(1)首先引入依赖

<!-- 验证码 -->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

(2)KaptchaConfig配置。

主要对图片边框、字体颜色、图片宽高、字体大小、验证码长度等进行设置。

 

package com.neuedu.controller.back;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.Properties;

@Component
public class KaptchaConfig {
    @Bean
    public DefaultKaptcha getDefaultKaptcha(){
        com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();
        Properties properties = new Properties();
        //图片边框
        properties.put("kaptcha.border", "no");
        //字体颜色
        properties.put("kaptcha.textproducer.font.color", "black");
        //图片宽
        properties.put("kaptcha.image.width", "150");
        //图片高
        properties.put("kaptcha.image.height", "40");
        //字体大小
        properties.put("kaptcha.textproducer.font.size", "30");
        //session key
        properties.put("kaptcha.session.key", "verifyCode");
        //验证码长度
        properties.put("kaptcha.textproducer.char.space", "5");
        Config config = new Config(properties);
        defaultKaptcha.setConfig(config);

        return defaultKaptcha;
    }
}

(3)CommonController,生产验证码字符串并保存到session中,使用生成的验证码字符串返回一个BufferedImage对象并转换为byte写入到byte数组中;定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组。

package com.neuedu.controller.back;

import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;

@Controller
public class CommonController {

    @Autowired
    private DefaultKaptcha captchaProducer;

    @GetMapping("/common/kaptcha")
    public void defaultKaptcha(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
        byte[] captchaOutputStream = null;
        ByteArrayOutputStream imgOutputStream = new ByteArrayOutputStream();
        try {
            //生产验证码字符串并保存到session中
            String verifyCode = captchaProducer.createText();
            httpServletRequest.getSession().setAttribute("verifyCode", verifyCode);
            // 使用生成的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
            BufferedImage challenge = captchaProducer.createImage(verifyCode);
            ImageIO.write(challenge, "jpg", imgOutputStream);
        } catch (IllegalArgumentException e) {
            httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        // 定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
        captchaOutputStream = imgOutputStream.toByteArray();
        httpServletResponse.setHeader("Cache-Control", "no-store");
        httpServletResponse.setHeader("Pragma", "no-cache");
        httpServletResponse.setDateHeader("Expires", 0);
        httpServletResponse.setContentType("image/jpeg");
        ServletOutputStream responseOutputStream = httpServletResponse.getOutputStream();
        responseOutputStream.write(captchaOutputStream);
        responseOutputStream.flush();
        responseOutputStream.close();
    }
}

11.模态框的实现?

SweetAlert

12.模糊搜索如何实现?排序如何实现?

<select id="findCommodityList" parameterType="Map" resultMap="BaseResultMap">
  select shopid, shopname, description, picture, price, flag, userid, typeid, status,
  create_time, update_time, sub_pictures, category
  from commodity
  where flag = 0
  <if test="keyword!=null">
  AND (shopname like CONCAT('%',#{keyword},'%' ) or category like CONCAT('%',#{keyword},'%' ))
  </if>
  <if test="status!=null">
    AND status = #{status}
  </if>
  <if test="typeid!=null">
    AND typeid = #{typeid}
  </if>
  order by shopid desc
  <if test="start!=null and limit!=null">
    limit #{start},#{limit}
  </if>
</select>

13.项目部署

(1)购买阿里云服务器

(2)Xshell连接阿里云(Linux下应用Xshell通过SSH连接云服务器)

(3)开放端口

(4)配置线上环境

    创建普通用户

    安装jdk&tomcat&mysql

(5)线上部署

spring boot项目打包成jar包,运行jar包,通过java -jar xx.jar

在命令行中进行打包,首先删除掉项目中的target目录

mvn clean package -DskipTests //打包,跳过单元测试

等待打包成功,显示BUILD SUCCESS,在项目目录下生成一个target目录,找到xx.jar文件上传到Linux中,上传的位置,总是上传到Linux下所在的当前目录。

设置成一个后台进程,关闭Xshell后依然可以运行,执行命令nohup java -jar busines.jar &

将数据库部署到服务器上

进入Linux的mysql中,首先上传数据库文件

输入命令mysql -u root -p,输入密码。构建数据库。

连接支付宝的沙箱环境,进行网站支付,需要在支付宝开放平台的开发者中心的沙箱环境中修改回调地址。

  • 11
    点赞
  • 172
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值