@

目录

  • 自己添加的后端管理页面
    • 视频演示效果
    • 论文地址
    • 后台代码视频实现讲解思路
    • 1. 商品管理
    • 2.商品分类管理
    • 3.商品地址管理
    • 4.用户中心管理
    • 4. 用户权限管理
    • 5.订单管理
      • 5.1
    • 6.商品品牌管理
  • 锋迷商城项目
      • 1.通过Maven聚合工程搭建项目:
        • 1. 创建一个Maven的父项目,然后修改它的pom.xml文件,可以删除src等一些没有用的目录
        • 2.在父项目下面创建多个module,包括(common,beans,mapper,service,api)把它们全部打包成jar包
      • 3.由于mapper层需要调用beans层(pojo),需要在pom.xml文件中,然后可以在mapper中加入相关的依赖。
      • 4.创建service需要调用mapper,和common,需要在pom.xml文件中加上
      • 5.api层需要接收前端的请求所以需要我们创建一个SpringBoot工程,你可以创建一个Maven工程,然后加入相关的依赖
      • 6.api子工程,对外提供接口
    • 锋迷商城数据库设计
      • 2.软件开发步骤
      • 3.数据库设计流程
      • 3.数据建模工具PDMan
        • Spu和Sku的区别
      • 4.锋城业务流程设计
        • 4.1用户管理9业务流程分析
      • 5接口介绍
        • 5.1接口规范
      • 5.2Swagger(自动生成服务器接口的规范性文档)
        • 5.2.1引入相关的依赖:
        • 5.2.2 创建相关的配置类
        • 5.2.3根据你的配置的端口号进行相关的测试
        • 5.2.4 swagger提供了一套注解对每个接口进行详细的说明
        • 5.2.5swagger-ui插件使用
          • 1.api的module加入依赖
          • 2.进行访问,然后可以使用它进行相关的测试
      • 一、锋迷商城设计及实现用户管理
        • 1.UserDao接口的创建:
        • 2.UserMapper.xml
        • 3.UserService
        • 4.UserServiceimpl:
        • 5.api模块的UserController:
        • 6.ResultVO一个和前端进行数据交互的类
        • 7.在common模块的MD5Utils类:
      • 二、逆向工程
        • 7.1逆向工程配置
        • 7.2在pom.xml文件中指定generatorConfig.xml文件的路径
      • 三、跨域问题
      • 四、前端页面的传值
        • 4.1Cookie使用(自定义封装一个js,cookie_utils.js)
        • 4.2localStorage
        • 4.3Vue实现登录
      • 五、前后端分离开发用户认证的问题
        • 5.1单体项目中:
        • 5.2前后端分离项目中
        • 基于token认证的用户代码实现
      • 六、JWT(json Web Token)一个别人封装好的工具类生成相关的token
      • 6.1生成JWT
        • 6.2使用拦截器进行拦截
      • 6.3使用请求头进行传递token
        • axios通过请求头传值 里面的参数用Headers 不用Params
        • 6.3.1 CheckTokenInterceptor类 前端会发送预险性请求(只有它通过以后才可以进行第二次请求),需要拦截器进行放行
      • 七首页的分类列表的的实现
        • 7.1接口实现
        • 7.2业务层实现
        • 控制层实现
      • 八、商品的推荐功能实现
        • 8.1 流程分析
        • 8.2接口开发
          • 8.2.1数据库的实现
        • ProductMapper文件:
        • ProductImgMapper文件:
        • ProductMapper.xml文件实现
      • 8.2.2业务层实现
        • 8.2.3控制层实现
      • 九、商品详情显示(在Introduction.html进行相关的显示)
        • 9.1接口实现
        • 9.1.1 商品详情接口
      • 十、显示商品评价的信息(通过用户和商品评论表进行相关的连表查询)
        • 10.1 新建的VO,ProductCommentsVO (一对一的连表查询可以不用在实体类中声明另一个实体类)
    • 十一、添加购物车的功能实现
        • 10.1流程分析:
        • 10.2数据库的相关的操作
        • 10.2.1 购买的数量的前端实现在vue的methods中添加+和-的点击事件
        • 10.2.2给加入购物车这个按钮添加点击事件
    • 十二、添加购物车时候用户未登录
        • 12.1 添加购物车用户未登录,业务处理方式:
        • 12.2我们使用第三种难度最大的来
        • 12.3使用Layui进行添加购物车成功/失败的提示
          • 12.3.1声明layui的弹窗组件
        • 12.3.2成功失败进行提示
    • 十三购物车的列表
        • 13.1数据库dao接口的实现
        • 13.2pojo接口实现
        • 13.3修改购物车
          • 13.31通过这个进行购物车数量的修改:
          • 13.32changNum函数进行实现:
    • 十四购物车提交订单结算功能实现
      • 14.1实现流程分析
    • 十五、订单提交及支付流程
      • 15.1流程分析
      • 15.2订单添加接口实现
      • 15.3数据库操作
      • 15.4serviceimpl层实现 注意:这个方法需要加上@Transactional,也就是订单生成的时候,快照也必须生成
    • swagger报错解决
    • 十六 商品个人中心订单信息的查询
      • 16.1 流程分析
        • sql语句
        • OrderMapper.xml文件:
      • 16.2 接口开发
        • 16.2.1 Service层接口开发
      • 16.2.2 Controller层实现
      • 16.2.3前端使用Vue+ElementUI实现分页功能
        • 1. 引入cdn
        • 2. data中定义相关数据
        • 3.分页的相关的方法
        • 4. 分页的表格
        • Linux的常用 的命令的复习
      • Linux系统安装jdk
      • Linux安装Tomcat
          • 如果你的项目是部署在Tomcat上面的,你可以把你的项目打成war包,放在tomcat的weapp目录下面,运行tomcat即可进行该项目
      • Linux安装mysql(在线安装)
    • 20.锋迷项目的后端云部署
      • 20.1企业项目当中需要进行修改的东西:
        • 20.11在你的Linux中建立一个目录用来存放你的jar包:
    • 21.前端的项目的部署在云服务器上面
    • Tomcat作为前端项目的弊端
      • 1.前端会有大量的请求,Tomcat的弊端(难以满足高并发的,大约是2000-3000,使用Niginx可以提高高并发的承受,大约2万)
    • 22.Nginx
    • 23.前端项目部署在Nginx上面
    • 24.Linux安装Nginx(在线安装)
      • 24.1 安装编译工具(nginx安装之前需要编译)
      • 24.2安装PCRE
      • 24.3安装SSL库
      • 24.4安装zlib库
      • 24.5下载Nginx

自己添加的后端管理页面视频演示效果

[video(video-CZIQF8d5-1652505187791)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=641370075)(image-https://img-blog.csdnimg.cn/img_convert/6fc48aff3f62b207e20ca7badb21395a.png)(title-毕业设计SpringBoot+Vue+ElementUI商城系统实现(有后台))]

论文地址

商城论文地址

后台代码视频实现讲解思路

[video(video-zgz2Gybc-1667056389114)(type-bilibili)(url-https://player.bilibili.com/player.html?aid=816242633)(image-https://img-blog.csdnimg.cn/img_convert/69a030b2c0a14349f093065947c707ae.jpeg)(title-毕业设计锋迷商城手敲后台管理,实现逻辑讲解,代码讲解)]

b站地址

1. 商品管理


2.商品分类管理

3.商品地址管理

4.用户中心管理

4. 用户权限管理5.订单管理5.16.商品品牌管理锋迷商城项目

使用Maven聚合项目进行创建(一个maven的父项目多个maven的子项目),

可以在父项目pom.xml文件中加上:

pom

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKHt478Q-1633568521449)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210812151308862.png)]

1.通过Maven聚合工程搭建项目:1. 创建一个Maven的父项目,然后修改它的pom.xml文件,可以删除src等一些没有用的目录

pom

2.在父项目下面创建多个module,包括(common,beans,mapper,service,api)把它们全部打包成jar包

pom.xml加上

jar

3.由于mapper层需要调用beans层(pojo),需要在pom.xml文件中,然后可以在mapper中加入相关的依赖。

                       org.example            beans            2.0.1            

4.创建service需要调用mapper,和common,需要在pom.xml文件中加上

             org.example            mapper            2.0.1                            org.example            common            2.0.1        

5.api层需要接收前端的请求所以需要我们创建一个SpringBoot工程,你可以创建一个Maven工程,然后加入相关的依赖6.api子工程,对外提供接口

总的说父项目的所以依赖可以被子项目引用,子项目也可以单独的添加所需的依赖

锋迷商城数据库设计2.软件开发步骤

  • 提出问题

  • 可行性分析(技术(一般可以相关人员实现),成本,法律法规)

  • 概要设计

    • 系统设计(技术选型,架构模式)
    • 数据库设计
    • UI设计
    • 业务流程设计
  • 详细设计

    • 实现步骤(业务流程的实现细节)
  • 编码

    • 根据设计好的实现步骤进行代码实现
    • 开发过程使用单元测试
  • 测试

    • 集成测试
    • 功能测试(墨盒)
    • 性能测试(白盒)高并发,压力测试
  • 交付/部署实施

    3.数据库设计流程

  • 根据功能分析出数据库实体(javaBean)

    • 商品,订单,购物车,用户,地址…
  • 提取实体属性

    • spu商品(id,商品名称,商品图片,商品描述…)

    • 1 min10 ….. ….

    • sku(skuId, 参数 , 价格 商品id

    • 101 内存8G\存储128G 2999 1

    • 102 内存12G\存储256G 3999 1

    • 地址(姓名,地址,电话…..)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P8zP9MYA-1633446686624)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210814172548189.png)]

可以知道价格的依赖于参数的改变而改变,参数依赖于id改变,不满足数据库设计表的要求,可以设计两张表进行实现。

  • 使用数据库的第三范式进行检查数据项是否合理
  • 分析实体关系图:E-R图 (一对一,一对多)
  • 数据库建模(三线图)建模工具(PdMan)
  • 建库建表-sql

3.数据建模工具PDMan

  • 可视化创建数据库表(数据表

  • 视图显示表之间的关系(关系图)

  • 导出sql指令(模型—导出DDL脚本

  • 记录数据库模型版本管理

  • 可以连接数据库直接生成表

    Spu和Sku的区别

  • spu(Standard Product Unit):商品信息聚合的最小 单位。通俗讲属性值,特性相同的商品可以称为一个SPU.

    产品: 荣耀8 小米10

  • sku(Stock Keeping Unit)最小存货单元,定义为保存最小库存的控制最小可用单元

    sku 荣耀8 8G/128G 10

    sku 荣耀8 4G/124G 20

    注意一下 :订单表的设计功能:因为订单表只要用户一下订单,订单表的相关信息就不可以进行改变 ,所以需要进行地址的的快照和商品信息的快照,这样就算你临时改变了价格的信息或者其他的也没有关系

    购物车的设计:

4.锋城业务流程设计

在企业开发中,当完成项目的需求分析,功能分析,数据库分析与设计后,项目组就会按照项目中的功能模块进行开发任务的分配。

每个人会被分配不同的功能

4.1用户管理9业务流程分析

单体架构:页面和控制之间可以进行跳转,同步请求控制器,流程控制由控制器来完成

前后端分离架构:前端和后端开发开发和部署,前端只能通过异步发送请求,后端只负责接收请求及参数,处理请求,返回结果

前端可以发送如图所示的请求:需要url,params

5接口介绍

狭义:的理解:就是控制器中可以接受用户请求的方法

标准定义:API(Application Programming interface)应用程序编程接口,就是软件系统不同组成部分衔接的约定。

5.1接口规范

作为后端程序员不仅要完成接口程序的开发,还要编写接口的说明文档—接口规范

5.2Swagger(自动生成服务器接口的规范性文档)

前后端分离规开发,后端需要编写接口说明文档,会耗费比较多的时间

swagger是一个用于生成服务器接口的的规范性文档,并且能够对接口进行测试的工具。

  • swagger作用
  • 生成接口规范性文档
  • 生成接口测试工具

5.2.1引入相关的依赖:

                    io.springfox            springfox-swagger2            2.9.2                            io.springfox            springfox-swagger-ui            2.9.2        

5.2.2 创建相关的配置类

可以在api这个module中进行相关的controller层的测试,建立一个config包下面的SwaggerConfig类进行相关的测试,加上@Configuration,@EnableSwagger2注解,然后进行配置相关的信息

package com.qfedu.fmmall.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.w3c.dom.DocumentType;import springfox.documentation.builders.ApiInfoBuilder;import springfox.documentation.builders.PathSelectors;import springfox.documentation.builders.RequestHandlerSelectors;import springfox.documentation.service.ApiInfo;import springfox.documentation.service.Contact;import springfox.documentation.spi.DocumentationType;import springfox.documentation.spring.web.plugins.Docket;import springfox.documentation.swagger2.annotations.EnableSwagger2;@Configuration@EnableSwagger2public class SwaggerConfig {    /*    * swagger生成我们的接口文档:    * 1.需要配置生成文档的信息    * 2.配置生成规则    *    * */    @Bean    public Docket docket(){//创建封面信息对象        ApiInfoBuilder apiInfoBuilder=new ApiInfoBuilder();//指定生成文档中的封面信息:文档标题,作者,版本        apiInfoBuilder.title("《锋迷商城》后端接口说明")                .description("此文档详细说明了锋迷商城项目后端接口规范")                .version("v 2.0.1")                .contact(new Contact("houge","www.houge.com","houge@hou.com"));        ApiInfo apiInfo=apiInfoBuilder.build();        Docket docket=new Docket(DocumentationType.SWAGGER_2) //指定文档风格                .apiInfo(apiInfo)                .select()                .apis(RequestHandlerSelectors.basePackage("com.qfedu.fmmall.controller"))//                定义了path之后只会为user开头的请求进行扫描 .paths(PathSelectors.regex("/user/"))//                PathSelectors.any()表示任何的请求                .paths(PathSelectors.any())                .build();        return docket;    }}

5.2.3根据你的配置的端口号进行相关的测试

http://localhost:8080/swagger-ui.html

5.2.4 swagger提供了一套注解对每个接口进行详细的说明

@Api(value=" 用户管理",tags="提供用户的登录和注册的接口")//这个接口可以直接放在@Controller注解下面

@ApiOperation 和ApiImplicitParams({ @ApiImplicitParam(dataType=””,name=”username”,value=””,required=true), @ApiImplictParm}) 这两个注解放在@RequestMapping(“/login”)请求之上,用来修饰方法和方法中的参数。

 @ApiOperation("用户登录的接口")    @ApiImplicitParams({            @ApiImplicitParam(dataType = "string",name = "username",value = "用户登录的账号",required = true),            @ApiImplicitParam(dataType = "string",name = "password",value = "用户登录的密码",defaultValue = "111111",required = false)    })    @RequestMapping("/login")//    @RequestParam可以有默认的参数    public ResultVO login(@RequestParam("username") String name,@RequestParam(value = "password",defaultValue = "111111") String pwd){        return userService.checkLogin(name,pwd);    }    @RequestMapping(value = "regist",metho

@ApiModel 和@ApiModelProperty接口参数返回一个对象类型时,需要在实体类中添加注解说明(也就是Beans这个Module进行相关的配置)

package com.qfedu.fmmall.entity;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructor@ApiModel(value = "用户的买家信息",description = "买家的相关的参数")public class User {    @ApiModelProperty(name = "用户id",required = false,dataType = "int")    private Integer userId;    @ApiModelProperty(dataType = "string",name = "买家姓名",required = true)    private String  userName;    @ApiModelProperty(dataType = "string",name = "买家密码",required = true)    private String userPwd;    @ApiModelProperty(dataType = "string",name = "买家真实姓名",required = true)    private String userRealname;    @ApiModelProperty(dataType = "string",name = "用户图片",required = true)    private String userImg;}
@ApiIgnore     接口方法注解,添加此注解的方法将不会生成到接口文档中

5.2.5swagger-ui插件使用1.api的module加入依赖

                            com.github.xiaoymin            swagger-bootstrap-ui            1.9.6        

2.进行访问,然后可以使用它进行相关的测试

http://ip:port/doc.html

一、锋迷商城设计及实现用户管理1.UserDao接口的创建:

package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.User;import org.springframework.stereotype.Repository;@Repositorypublic interface UserDao {//    用户注册    public int insert(User user);//   根据用户名进行登录的验证    public User queryByName(String name);}

2.UserMapper.xml

                                        select *from users where username=#{username}             insert into users(username,password,user_regtime,user_modtime) values (#{username},        #{password},#{userRegtime},#{userModtime})        

3.UserService

package com.qfedu.fmmall.service;import com.qfedu.fmmall.entity.User;import com.qfedu.fmmall.vo.ResultVO;public interface UserService {//    ResultVO是一个响应给前端的自定义的一个类。    public ResultVO checkLogin(String username, String pwd);//    用户注册    public ResultVO insert(String username, String pwd);}

4.UserServiceimpl:

package com.qfedu.fmmall.service.impl;import com.qfedu.fmmall.service.UserService;import com.qfedu.fmmall.dao.UserDao;import com.qfedu.fmmall.entity.User;import com.qfedu.fmmall.utils.MD5Utils;import com.qfedu.fmmall.vo.ResultVO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import java.util.Date;@Service@Transactional//使所有的线程都用这个对象,单例模式默认是开启的@Scope("singleton")public class UserServiceimpl implements UserService {    @Autowired    private UserDao userDao;//可以在UserDao上面加上userDao,这个不会报红,但是没有什么意义    @Override    public ResultVO checkLogin(String username, String pwd) {//        查询用户名        User user = userDao.queryByName(username);        if(user==null){//            用户名不正确            return new ResultVO(10001,"用户名不正确",null);        }else {            //密码使用MD5进行加密            String md5Pwd = MD5Utils.md5(pwd);            if(md5Pwd.equals(user.getPassword())){//          验证成功                return  new ResultVO(200,"登录成功",user);            }else {                //密码不正确                return  new ResultVO(10001,"密码错误",null);            }        }    }    @Transactional    @Override    public ResultVO insert(String username, String pwd) {//        判断这个用户是否被注册//        加上这个锁可以使用所有的注册都用这个userServiceimpl        synchronized (this){//            把密码进行MD5的加密            String password = MD5Utils.md5(pwd);            User user1 = userDao.queryByName(username);//表示用户名没有被注册过,可以进行注册            if (user1==null){//一个是注册时间,regtime,一个是修改时间modtime                User user=new User(username,password,new Date(),new Date());                int i = userDao.insert(user);                if(i>0){                    return new ResultVO(1000,"注册成功",null);                }else {                    return new ResultVO(1001,"注册失败",null);                }            }//            判断一下用户名是否已经被注册,然后把数据返回前端,goodjob,Noone can influence you            else {                return new ResultVO(1001,"用户名已经被注册",null);            }        }    }}

5.api模块的UserController:

package com.qfedu.fmmall.vo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructor@ApiModel(value = "ResultVO对象",description = "响应封装的数据给前端")public class ResultVO {//    响应给前端的状态码    @ApiModelProperty(dataType = "int",value = "响应的状态码")    private  int code;//    响应给前端的提示消息    @ApiModelProperty(dataType = "string",value = "响应的消息")    private  String msg;//响应给前端的数据    @ApiModelProperty(dataType = "object",value = "响应数据的内容")    private  Object data;}

6.ResultVO一个和前端进行数据交互的类

package com.qfedu.fmmall.vo;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;@Data@AllArgsConstructor@NoArgsConstructor@ApiModel(value = "ResultVO对象",description = "响应封装的数据给前端")public class ResultVO {//    响应给前端的状态码    @ApiModelProperty(dataType = "int",value = "响应的状态码")    private  int code;//    响应给前端的提示消息    @ApiModelProperty(dataType = "string",value = "响应的消息")    private  String msg;//响应给前端的数据    @ApiModelProperty(dataType = "object",value = "响应数据的内容")    private  Object data;}

7.在common模块的MD5Utils类:

package com.qfedu.fmmall.utils;import java.math.BigInteger;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;//MD5 生成器public class MD5Utils {public static String md5(String password){//生成一个md5加密器try {MessageDigest md = MessageDigest.getInstance("MD5");//计算MD5 的值md.update(password.getBytes());//BigInteger 将8位的字符串 转成16位的字符串 得到的字符串形式是哈希码值//BigInteger(参数1,参数2) 参数1 是 1为正数 0为0 -1为负数return new BigInteger(1, md.digest()).toString(16);} catch (NoSuchAlgorithmException e) {e.printStackTrace();}return null;}}

二、逆向工程

根据创建好的表,生成实体类,和DAO层、映射文件

在Dependencies下面加入依赖,这个依赖是一个Mybatis的maven插件

                        org.mybatis.generator            mybatis-generator-maven-plugin            1.3.5                            ${basedir}/src/main/resources/generator/generatorConfig.xml                                                                        mysql                    mysql-connector-java                    5.1.46                                                    tk.mybatis                    mapper                    4.1.5                                  

7.1逆向工程配置

在resources的generator目录下面创建generatorConfig.xml

  1. 需要修改数据库的配置

  2. 需要修改pojo,mapper,Mapper.xml文件生成位置的配置

  3.         
  4.                            
  5. 指定你的用Configuration generatorConfig.xml文件的路径

  6. 注意一下你的文件一定想要有空格什么东西的

    <!--    -->                                                                                                                                                                                                                                                                                                

7.2在pom.xml文件中指定generatorConfig.xml文件的路径

加上了这个:

                 ${basedir}/src/main/resources/generator/generatorConfig.xml            
                    org.mybatis.generator            mybatis-generator-maven-plugin            1.3.5                            ${basedir}/src/main/resources/generator/generatorConfig.xml                                                            mysql                    mysql-connector-java                    5.1.46                                                    tk.mybatis                    mapper                    4.1.5                                    

三、跨域问题

解决方案:
后端解决办法:在UserController加上@CrossOrigin注解

前端通过Ajax请求跨域登录:

$("#submitBtn").click(function(){var name=$("#userName").val();var pwd=$('#userPwd').val(); $.get("http://localhost:8080/user/login",{ username:name, password:pwd, },function(res){ console.log(res); },"json" )})

前端使用JSONP设置,后端使用@CrossOrigin注解解决—设置响应头header允许跨域。
debugger;前端 可以加上代码debugger进行相关的调试。可以直接进行前端的校验

四、前端页面的传值

cookie和localstorage可以进行前端的页面之间的传值

Cookie浏览器端的缓存文件:大小受浏览器的限制。

LocalStorage:为了存储更大容量的数据

区别:cookie可以和后台进行传值,localStorage只可以在前端存储值,但是存储的时间长。

4.1Cookie使用(自定义封装一个js,cookie_utils.js)

var opertor="=";function getCookieValue(keyStr){var s=window.document.cookie;var arr=s.split("; ");for(var i=0;i<arr.length;i++){var str=arr[i];var k=str.split(opertor)[0];var v=str.split(opertor)[1];if(k==keyStr){value=v;break;}}return value;}function setCookieValue(key,value){document.cookie=key+opertor+value;}

A页面设置值:

function(res){  console.log(res);  if(res.code==1000){// 获取前端传过来的数据 datavar userInfo=res.data;// cookie和localstorage可以进行前端的页面之间的传值setCookieValue("username",userInfo.username);setCookieValue("userImg",userInfo.userImg);window.location.href="index.html";  }else{$("#tips").html("");  }

B页面取值:

var name=getCookieValue("username"); var userImg=getCookieValue("userImg"); console.log(name+userImg);

4.2localStorage

A页面:

localStorage.setItem("user",JSON.stringify(userInfo));

B页面:

var jsonStr=localStorage.getItem("user");// 把json串转换为对象var userInfo=eval("("+jsonStr+")");// 把取到的值消失localStorage.removeItem("user");console.log(userInfo);

4.3Vue实现登录

data:{username:"",password:"",tips:" ",colorStyle:"",isRight:false,},methods:{doSubmit:function() {// 校验成功if(vm.isRight){var url=baseUrl+"/user/login";axios.get(url,{params:{username:vm.username,password:vm.password} }).then((res)=>{console.log(res);var vo=res.data;if(vo.code==1){window.location.href="index.html";}else{vm.tips="账号或者密码错误";}});}else{vm.tips="请输入正确的用户名和密码";vm.colorStyle="color:red"}            //  1.进行数据的校验            if(vm.username==" "){                vm.tips="请输入用户名";                vm.colorStyle="color:red";            }                      },         checkInfo:function(){            if(vm.username==""){                vm.tips="请输入用户名";                this.colorStyle="color:red";vm.isRight=false;            }else if(vm.username.length20){                vm.tips="账号长度必须为6-20";                vm.colorStyle="color:red";vm.isRight=false;            }else{// 校验密码if(vm.password==" "){                vm.tips="请输入密码";                this.colorStyle="color:red";vm.isRight=false;            }else if(vm.password.length16){vm.tips="密码长度为6-16";                this.colorStyle="color:red";}else{vm.tips=" ";vm.isRight=true;}}         }}

from表单(用@keyup进行表单的输入的绑定):

五、前后端分离开发用户认证的问题5.1单体项目中:

可以知道每台服务器中存在多个Session,只是id不相同,Cookie中可以存放sessionId,然后判断是是不是同一个session

在单体项目中用户怎么认证的?

在单体项目中视图资源和控制器都在同一台服务器,用户的多次请求老师基于同一个会话,可以基于session进行会话的验证:

  1. 用户登录将信息存放在session中
  2. 根据session中是否有用户信息来判断用户是否可以进行登录。

5.2前后端分离项目中

可以知道使用token实现用户验证,token存在于cookie中(同一台服务器可以访问cookie),然后验证token是否正确

基于token认证的用户代码实现

在commons模块中引入

package com.qfedu.fmmall.utils;import java.util.Base64;//base64 加密 解密 激活邮件的时候 为 邮箱地址 code验证码 进行加密//当 回传回来后 进行邮箱地址 和 code 的解密public class Base64Utils {//加密public static String encode(String msg){return Base64.getEncoder().encodeToString(msg.getBytes());}//解密public static String decode(String msg){return new String(Base64.getDecoder().decode(msg));}}

登录成功生成token:UserController

package com.qfedu.fmmall.controller;import com.qfedu.fmmall.entity.Users;import com.qfedu.fmmall.service.UserService;import com.qfedu.fmmall.vo.ResultVO;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import io.swagger.annotations.ApiOperation;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;/*@Controller@ResponseBody*/@RestController@RequestMapping("/user")@CrossOrigin@Api(value = "提供用户的登录和注册的接口",tags = "用户管理")public class UserController {    @Autowired    private UserService userService;//    @ApiIgnore加上这个注解会swagger忽略这个方法    @ApiOperation("用户登录的接口")    @ApiImplicitParams({            @ApiImplicitParam(dataType = "string",name = "username",value = "用户登录的账号",required = true),            @ApiImplicitParam(dataType = "string",name = "password",value = "用户登录的密码",required = true)    })    @RequestMapping("/login")//    @RequestParam可以有默认的参数    public ResultVO login(@RequestParam("username") String name,@RequestParam(value = "password") String pwd){        return userService.checkLogin(name,pwd);    }    @ApiOperation(value = "用户注册")    @PostMapping("/regist")    @ApiImplicitParams({            @ApiImplicitParam(dataType = "string",name = "username",value = "用户注册的账号",required = true),            @ApiImplicitParam(dataType = "string",name = "password",value = "用户注册的密码",required = true)    })//    前端用user传值,后端可以用users 接收     public ResultVO register(@RequestBody Users users){        return userService.insert(users.getUsername(),users.getPassword());    }}

然后在UserServiceimpl中进行token的加密:

// 如果登录成功,则需要生成令牌token(token就是按照规则生成的字符串)
String token= Base64Util.encode(username+”roothouzhicong”);

package com.qfedu.fmmall.service.impl;import com.qfedu.fmmall.dao.UsersMapper;import com.qfedu.fmmall.entity.Users;import com.qfedu.fmmall.service.UserService;import com.qfedu.fmmall.utils.MD5Utils;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import org.apache.logging.log4j.util.Base64Util;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import tk.mybatis.mapper.entity.Example;import java.util.Date;import java.util.List;@Service@Transactional//使所有的线程都用这个对象,单例模式默认是开启的@Scope("singleton")public class UserServiceimpl implements UserService {    @Autowired    private UsersMapper userDao;//可以在UserDao上面加上userDao,这个不会报红,但是没有什么意义    @Override    public ResultVO checkLogin(String username, String pwd) {//        查询用户名        Example example = new Example(Users.class);        Example.Criteria criteria = example.createCriteria();        criteria.andEqualTo("username",username);        List users = userDao.selectByExample(example);//        if(users.size()==0){//            用户名不正确            return new ResultVO(10001,"用户名不正确",null);        }else {            //密码使用MD5进行加密            String md5Pwd = MD5Utils.md5(pwd);            System.out.println(users.get(0).getPassword());            if(md5Pwd.equals(users.get(0).getPassword())){//                如果登录成功,则需要生成令牌token(token就是按照规则生成的字符串)                String token= Base64Util.encode(username+"roothouzhicong");                //          验证成功                return  new ResultVO(ResultStatus.OK,token,users.get(0));            }else {                //密码不正确                return  new ResultVO(ResultStatus.NO,"密码错误",null);            }        }    }    @Transactional    @Override    public ResultVO insert(String username, String pwd) {//        判断这个用户是否被注册//        加上这个锁可以使用所有的注册都用这个userServiceimpl        synchronized (this){//            把密码进行MD5的加密            String password = MD5Utils.md5(pwd);            //        查询用户名            Example example = new Example(Users.class);            Example.Criteria criteria = example.createCriteria();            criteria.andEqualTo("username",username);            List users = userDao.selectByExample(example);//表示用户名没有被注册过,可以进行注册            if (users.size()==0){//一个是注册时间,regtime,一个是修改时间modtime                Users user=new Users(username,password,new Date(),new Date());                int i = userDao.insert(user);                if(i>0){                    return new ResultVO(ResultStatus.OK,"注册成功",null);                }else {                    return new ResultVO(ResultStatus.NO,"注册失败",null);                }            }//            判断一下用户名是否已经被注册,然后把数据返回前端,goodjob,Noone can influence you            else {                return new ResultVO(ResultStatus.NO,"用户名已经被注册",null);            }        }    }}

前端设置token:

doSubmit:function() {// 校验成功if(vm.isRight){var url=baseUrl+"/user/login";axios.get(url,{params:{username:vm.username,password:vm.password} }).then((res)=>{console.log(res);var vo=res.data;console.log(vo);if(vo.code==1){ // 如果登录成功就把token存储到时cookie中setCookieValue("token",vo.msg); window.location.href="index.html";}else{vm.tips="账号或者密码错误";}});

前端的购物车获取token:

// 进入购物车时要访问购物车列表的接口shopController接口var baseUrl="http://localhost:8080/";    var vm=new Vue({el:"#app",data:{token:"",},created() {this.token=getCookieValue("token");console.log("token="+this.token);axios({method:"get",url:baseUrl+"shopcart/list",params:{token:this.token,}}).then(function (res) {console.log(res);});},})

登录进行来可以把购物车获取token,前端的token用CookieUtils.js封装的包进行相关的获取,

package com.qfedu.fmmall.controller;import com.qfedu.fmmall.utils.Base64Utils;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@CrossOrigin@Api(value = "提供购物车业务相关的接口",tags = "购物车管理接口")@RequestMapping("/shopcart")public class ShopCartController {    @RequestMapping("/list")    @ApiImplicitParam(dataType = "string",name = "token",value = "登录的一个标志",required = true)    public ResultVO shopcartList(String token){//        校验输入的token看看是否是用户自己登录的token       //解密         String decode = Base64Utils.decode(token);        if(token==null){            return new ResultVO(ResultStatus.NO, "请先登录", null);        }else if(decode.endsWith("roothouzhicong")) {            System.out.println("购物车列表相关的接口------------");            return new ResultVO(ResultStatus.OK, "success", null);        }else {            return new ResultVO(ResultStatus.NO, "登录已经过期,请重新登录!!", null);        }    }}

六、JWT(json Web Token)一个别人封装好的工具类生成相关的token

  1. 用自定义的token生成的时效性不可以进行定义
  2. 安全性较差

JWT结构:

6.1生成JWT

  • 添加依赖:

                        com.auth0            java-jwt            3.10.3                        io.jsonwebtoken        jjwt        0.9.1    

UserServiceimpl(登录成功)生成token:

 HashMap map=new HashMap();                JwtBuilder builder= Jwts.builder();                String token = builder.setSubject(username)   //主题就是token中携带的数据                        .setIssuedAt(new Date()) //设置token的生成时间                        .setId(users.get(0).getUserId() + "") //设置用户的id为tokenid                        .setClaims(map)                         //map中可以存放用户的角色权限信息                        .setExpiration(new Date(System.currentTimeMillis() + 24 * 60 * 60 * 1000)) //设置token的过期时间                        .signWith(SignatureAlgorithm.HS256, "houzhicong") //设置加密的方式                        .compact();                //          验证成功

前端ShopCart.html通过Cookie获取生成的token:

// 进入购物车时要访问购物车列表的接口shopController接口var baseUrl="http://localhost:8080/";    var vm=new Vue({el:"#app",data:{token:"",},created() {this.token=getCookieValue("token");console.log("token="+this.token);axios({method:"get",url:baseUrl+"shopcart/list",Headers:{token:this.token,}}).then(function (res) {console.log(res);});},})

后端ShopController进行解析Token:

package com.qfedu.fmmall.controller;import com.qfedu.fmmall.utils.Base64Utils;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import io.jsonwebtoken.Claims;import io.jsonwebtoken.Jws;import io.jsonwebtoken.JwtParser;import io.jsonwebtoken.Jwts;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@RestController@CrossOrigin@Api(value = "提供购物车业务相关的接口",tags = "购物车管理接口")@RequestMapping("/shopcart")public class ShopCartController {    @RequestMapping("/list")    @ApiImplicitParam(dataType = "string",name = "token",value = "登录的一个标志",required = true)    public ResultVO shopcartList(String token){//        校验输入的token看看是否是用户自己登录的token//        String decode = Base64Utils.decode(token);        if(token==null){            return new ResultVO(ResultStatus.NO, "请先登录", null);        }else {            JwtParser parser= Jwts.parser();            parser.setSigningKey("houzhicong");//解析token 必须和生成token时候生成的密码一致//            如果token正确(密码正确,有效期内) 则正常执行,否则抛出异常            try{                Jws claimsJws=parser.parseClaimsJws(token);                Claims body=claimsJws.getBody();//获取token中的用户数据                String subject=body.getSubject();//获取生成token设置subject               String v1=body.get("key1",String.class);//获取生成token时存储的Claims的map中的值                return new ResultVO(ResultStatus.OK, "success", null);            }catch (Exception e){                return new ResultVO(ResultStatus.NO, "登录已经过期,请重新登录!!", null);            }        }    }}

6.2使用拦截器进行拦截

  1. 创建一个CheckTokenInterceptor
  2. 创建一个拦截器的类 InterceptorConfig
6.3.1有
package com.qfedu.fmmall.config;import com.qfedu.fmmall.interceptor.CheckTokenInterceptor;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configurationpublic class InterceptorConfig implements WebMvcConfigurer {    @Autowired    private CheckTokenInterceptor checkTokenInterceptor;    @Override    public void addInterceptors(InterceptorRegistry registry) {        registry.addInterceptor(new CheckTokenInterceptor())                .addPathPatterns("/**")                .excludePathPatterns("/user/**"                ,"/doc.html"                ,"/swagger-ui/**");    }}

6.3使用请求头进行传递token

前端但凡访问受限资源,都必须携带token请求,token可以通过请求行(params),请求头(header),以及请求体(data)传递,但习惯使用header传递

axios通过请求头传值 里面的参数用Headers 不用Params

axios({method:"get",url:baseUrl+"shopcart/list",Headers:{token:this.token,}}).then(function (res) {console.log(res);});},

6.3.1 CheckTokenInterceptor类 前端会发送预险性请求(只有它通过以后才可以进行第二次请求),需要拦截器进行放行

package com.qfedu.fmmall.interceptor;import com.fasterxml.jackson.databind.ObjectMapper;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import io.jsonwebtoken.*;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;@Configurationpublic class CheckTokenInterceptor implements HandlerInterceptor {//   打ov 可以看到它的方法    @Override    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        String token = request.getParameter("token");//        System.out.println("token----------");//        前端会发送预险性请求        String method = request.getMethod();        if("options".equalsIgnoreCase(method)){            return true;        }        if(token==null){//            提示用户进行登录            PrintWriter out = response.getWriter();            ResultVO resultVO= new ResultVO(ResultStatus.NO, "请先登录", null);//         抽出一个方法进行            doResponse(response,resultVO);//            拦截            return  false;        }else {//            验证token            try{                JwtParser parser= Jwts.parser();                parser.setSigningKey("houzhicong");                Jws claimsJws=parser.parseClaimsJws(token);                return true;            }catch (ExpiredJwtException e){                ResultVO resultVO= new ResultVO(ResultStatus.NO, "登录过期,请重新登录", null);                doResponse(response,resultVO);                return false;            }            catch (UnsupportedJwtException e){                ResultVO resultVO= new ResultVO(ResultStatus.NO, "Token不合法,请自重", null);                doResponse(response,resultVO);                return false;            }            catch (Exception e){                ResultVO resultVO= new ResultVO(ResultStatus.NO, "请先登录", null);                doResponse(response,resultVO);                return false;            }        }    }    private void doResponse(HttpServletResponse response,  ResultVO resultVO) throws IOException {        response.setContentType("application/json");        response.setCharacterEncoding("utf-8");        PrintWriter out = response.getWriter();//        写上Json格式的resultVO        String s = new ObjectMapper().writeValueAsString(resultVO);        out.println(s);        out.flush();        out.close();    }}

七首页的分类列表的的实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wQm4qlh3-1633446686637)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210823182623779.png)]

得出结论:数据量较少的情况,使用一次性查询,数据量较多使用多次查询

方案一:一次性查询三级分类

  • 优点只需一查询
  • 缺点:数据库查询效率较低,页面首次加载的速度较慢

方案二:

  • 先只查询一级分类,用户点击/鼠标移动到一级分类,动态加载二级分类
  • 缺点:需要多次连接数据库

7.1接口实现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WFClkTnv-1633446686638)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210823204928346.png)]

一次性查询出来的sql语句:inner join 和left join 的区别 left join 左边没有关联的数据也会全部显示

select c1.category_id 'category_id1',c1.category_name 'category_name',c1.category_level 'category_level',c1.parent_id 'parent_id',c1.category_icon 'category_icon',c1.category_slogan 'category_slogan',c1.category_pic 'category_pic',c1.category_bg_color 'category_bg_color',c2.category_id 'category_id2',c2.category_name 'category_name2',c2.category_level 'category_leve2',c2.parent_id 'parent_id2',c3.category_id 'category_id3',c3.category_name 'category_name3',c3.category_level 'category_leve3',c3.parent_id 'parent_id3'from category c1left join category c2 on c2.parent_id=c1.category_idleft join category c3 on c3.parent_id=c2.category_idwhere c1.category_level=1
select *from category c1  inner join category c2 on c2.parent_id=c1.category_id  left join category c3 on c3.parent_id=c2.category_id   where c1.category_level=1 
--根据父级分类的parent_id进行查询 1 级 parent_id=0select *from category where parent_id=0,
  • 创建用于封装查询的类别信息CategoryVO

    在Beans模块中entity包下面创建一个CategoryVO实体类用于封装Category和前端 进行数据的响应,相对于Category多了这个属性

    //实体类中实现当前分类的子分类private List categories;        public List getCategories() {            return categories;        }        public void setCategories(List categories) {            this.categories = categories;        } 
  • 在CategoryMapper中定义一个函数

    package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.Category;import com.qfedu.fmmall.entity.CategoryVO;import com.qfedu.fmmall.general.GeneralDao;import java.util.List;public interface CategoryMapper extends GeneralDao {//使用连接查询实现分类列表查询    public List selectAllCategories();            //    子查询    public List selectAllCategories2(int parentId);}
  • 映射文件配置

                                                                                                                                                    selectc1.category_id 'category_id1',c1.category_name 'category_name',c1.category_level 'category_level',c1.parent_id 'parent_id',c1.category_icon 'category_icon',c1.category_slogan 'category_slogan',c1.category_pic 'category_pic',c1.category_bg_color 'category_bg_color',c2.category_id 'category_id2',c2.category_name 'category_name2',c2.category_level 'category_leve2',c2.parent_id 'parent_id2',c3.category_id 'category_id3',c3.category_name 'category_name3',c3.category_level 'category_leve3',c3.parent_id 'parent_id3'from category c1left join category c2 on c2.parent_id=c1.category_idleft join category c3 on c3.parent_id=c2.category_idwhere c1.category_level=1             
使用子查询实现分类列表的查询:```xml                                          <!--  这里的column="category_id"将等于//    子查询    public List selectAllCategories2(int parentId);里面的parentId;-->          select     category_id,category_name,category_level,parent_id,category_icon,category_slogan,category_pic,category_bg_colorfrom category where parent_id=#{parentId};  

7.2业务层实现

CategoryService

package com.qfedu.fmmall.service;import com.qfedu.fmmall.vo.ResultVO;public interface CategoryService {    public ResultVO queryAllCategory();}

CategoryServiceimpl:

package com.qfedu.fmmall.service.impl;import com.qfedu.fmmall.dao.CategoryMapper;import com.qfedu.fmmall.entity.CategoryVO;import com.qfedu.fmmall.service.CategoryService;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import org.springframework.stereotype.Service;import javax.annotation.Resource;import java.util.List;@Servicepublic class CategoryServiceimpl implements CategoryService {    @Resource    private CategoryMapper categoryMapper;    @Override    public ResultVO queryAllCategory() {        List categoryVOS = categoryMapper.selectAllCategories2(0);        return new ResultVO(ResultStatus.OK,"success",categoryVOS);    }}

控制层实现

indexController实现:

@Autowired    private CategoryService categoryService;    @RequestMapping("category-list")    @ApiOperation("商品分类查询接口")    public ResultVO queryAllCategory(){        return categoryService.queryAllCategory();    }

八、商品的推荐功能实现8.1 流程分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yol4wuqR-1633446686638)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210828192719883.png)]

推荐最新上架的商品

8.2接口开发8.2.1数据库的实现

  • sql语句实现

    -- 商品推荐查询最新上架信息select *from product order by create_time desc limit 0,3;-- 商品图片查询 根据商品id查询商品图片select *from product_img where item_id=2;

    在子工程beans工程下面创建ProductVO (加上了这个属性 private List imgs;因为一个商品包含多张表)

    package com.qfedu.fmmall.entity;import javax.persistence.Column;import javax.persistence.Id;import java.util.Date;import java.util.List;public class ProductVO {    /**     * 商品id     */    @Id    @Column(name = "product_id")    private Integer productId;    /**     * 商品名称     */    @Column(name = "product_name")    private String productName;    /**     * 商品分类id     */    @Column(name = "category_id")    private Integer categoryId;    /**     * 一级分类外键id     */    @Column(name = "root_category_id")    private Integer rootCategoryId;    /**     * 销量     */    @Column(name = "sold_num")    private Integer soldNum;    /**     * 商品状态     */    @Column(name = "product_status")    private Integer productStatus;    /**     * 商品内容     */    private String content;    /**     * 创建时间     */    @Column(name = "create_time")    private Date createTime;    /**     * 更新时间     */    @Column(name = "update_time")    private Date updateTime;    private List imgs;    public List getImgs() {        return imgs;    }    public void setImgs(List imgs) {        this.imgs = imgs;    }    @Override    public String toString() {        return "ProductVO{" +                "imgs=" + imgs +                '}';    }    /**     * 获取商品id     *     * @return product_id - 商品id     */    public Integer getProductId() {        return productId;    }    /**     * 设置商品id     *     * @param productId 商品id     */    public void setProductId(Integer productId) {        this.productId = productId;    }    /**     * 获取商品名称     *     * @return product_name - 商品名称     */    public String getProductName() {        return productName;    }    /**     * 设置商品名称     *     * @param productName 商品名称     */    public void setProductName(String productName) {        this.productName = productName == null ? null : productName.trim();    }    /**     * 获取商品分类id     *     * @return category_id - 商品分类id     */    public Integer getCategoryId() {        return categoryId;    }    /**     * 设置商品分类id     *     * @param categoryId 商品分类id     */    public void setCategoryId(Integer categoryId) {        this.categoryId = categoryId;    }    /**     * 获取一级分类外键id     *     * @return root_category_id - 一级分类外键id     */    public Integer getRootCategoryId() {        return rootCategoryId;    }    /**     * 设置一级分类外键id     *     * @param rootCategoryId 一级分类外键id     */    public void setRootCategoryId(Integer rootCategoryId) {        this.rootCategoryId = rootCategoryId;    }    /**     * 获取销量     *     * @return sold_num - 销量     */    public Integer getSoldNum() {        return soldNum;    }    /**     * 设置销量     *     * @param soldNum 销量     */    public void setSoldNum(Integer soldNum) {        this.soldNum = soldNum;    }    /**     * 获取商品状态     *     * @return product_status - 商品状态     */    public Integer getProductStatus() {        return productStatus;    }    /**     * 设置商品状态     *     * @param productStatus 商品状态     */    public void setProductStatus(Integer productStatus) {        this.productStatus = productStatus;    }    /**     * 获取商品内容     *     * @return content - 商品内容     */    public String getContent() {        return content;    }    /**     * 设置商品内容     *     * @param content 商品内容     */    public void setContent(String content) {        this.content = content == null ? null : content.trim();    }    /**     * 获取创建时间     *     * @return create_time - 创建时间     */    public Date getCreateTime() {        return createTime;    }    /**     * 设置创建时间     *     * @param createTime 创建时间     */    public void setCreateTime(Date createTime) {        this.createTime = createTime;    }    /**     * 获取更新时间     *     * @return update_time - 更新时间     */    public Date getUpdateTime() {        return updateTime;    }    /**     * 设置更新时间     *     * @param updateTime 更新时间     */    public void setUpdateTime(Date updateTime) {        this.updateTime = updateTime;    }}

    ProductMapper文件:

    package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.Product;import com.qfedu.fmmall.entity.ProductVO;import com.qfedu.fmmall.general.GeneralDao;import java.util.List;public interface ProductMapper extends GeneralDao {//    查询推荐商品信息    public List selectRecommendProducts();}

    ProductImgMapper文件:

    package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.ProductImg;import com.qfedu.fmmall.general.GeneralDao;import java.util.List;public interface ProductImgMapper extends GeneralDao {    public List selectProductImgByProductId(int productId);}

    ProductMapper.xml文件实现

    注意一下子查询 的语句:

     
                                                                                                  selectproduct_id,product_name,category_id,root_category_id,sold_num,product_status,content,create_time,update_timefrom product order by create_time desc limit 0,3;  

    8.2.2业务层实现

    package com.qfedu.fmmall.service;import com.qfedu.fmmall.entity.ProductVO;import com.qfedu.fmmall.vo.ResultVO;import java.util.List;public interface ProductService {    public ResultVO selectRecommendProducts();}

    8.2.3控制层实现

     @ApiOperation("商品推荐查询信息接口")    @RequestMapping(value = "/list-recommends",method = RequestMethod.GET)    public ResultVO selectProductRecommend(){        ResultVO resultVO = productService.selectRecommendProducts();        return resultVO;    }

九、商品详情显示(在Introduction.html进行相关的显示)

点击商品推荐,商品轮播图,商品的列表页面点击商品,就会进入到商品的详情页面。

  1. 获取商品id
  2. 可以查询商品的详情信息(商品的基本信息,商品套餐,商品图片信息。)
  3. 将商品参数返回给前端

9.1接口实现9.1.1 商品详情接口

商品基本信息(product),商品套餐(sku),商品图片(product_img)

  • SQL

    -- 根据商品id查询商品详情select *from product where product_id=3;-- 根据商品id查询商品图片详情select *from product_img where item_id=3;-- 根据商品id查询当前商品的套餐select *from product_sku where product_id=3;
  • 可以用子查询实现这个相关的操作

  • dao接口实现(通过product,product_img,product_sku三张表获取商品的详情信息)

    @Repositorypublic interface ProductMapper extends GeneralDao {//    查询推荐商品信息    public List selectRecommendProducts();}package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.ProductImg;import com.qfedu.fmmall.general.GeneralDao;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface ProductImgMapper extends GeneralDao {    public List selectProductImgByProductId(int productId);}package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.ProductSku;import com.qfedu.fmmall.general.GeneralDao;import org.springframework.stereotype.Repository;@Repositorypublic interface ProductSkuMapper extends GeneralDao {}
  • 业务层实现

//这里为不需要事务,但是如果某些事务如果调用了我也加入到事务中来//    事务默认的隔离级别是可重复读 repeateable read    @Transactional(propagation = Propagation.SUPPORTS)    public ResultVO selectProductBasicInfo(String productId) {//      1.查询商品的基本信息        Example example = new Example(Product.class);        Example.Criteria criteria = example.createCriteria();        criteria.andEqualTo("productId",productId);        criteria.andEqualTo("productStatus",1);        List products = productMapper.selectByExample(example);//        System.out.println(products);        if(products.size()>0){            //      2.查询商品的图片信息           Example example1 = new Example(ProductImg.class);            Example.Criteria criteria1 = example1.createCriteria();            criteria1.andEqualTo("itmeId",productId);            List productImgs = productImgMapperMapper.selectByExample(example1);//            System.out.println(productImgs);            //        3.查询商品的套餐信息            Example example2 = new Example(ProductSku.class);            Example.Criteria criteria2 = example2.createCriteria();            criteria2.andEqualTo("productId",productId);            criteria2.andEqualTo("status",1);            List productSkus = productSkuMapper.selectByExample(example2);//            System.out.println(productSkus);//            把所有的商品的详情信息放入HashMap当中进行使用            HashMap basicInfo=new HashMap();            basicInfo.put("product",products.get(0));            basicInfo.put("productImgs",productImgs);            basicInfo.put("productSkus",productSkus);            return new ResultVO(ResultStatus.OK,"success",basicInfo);        }else {            new ResultVO(ResultStatus.NO,"查询商品基本信息失败",null);        }        return null;    }
  • 控制层实现(这边把商品的详情的信息放到了ResultVO的Object中)
//    商品详情查询    @RequestMapping(value = "/detail/{pid}",method = RequestMethod.GET)    public ResultVO getProductBasicInfo(@PathVariable("pid") String productId){        ResultVO resultVO = productService.selectProductBasicInfo(productId);//        System.out.println(resultVO);        return resultVO;    }

十、显示商品评价的信息(通过用户和商品评论表进行相关的连表查询)

-- 根据评论的id查询评论信息,关联用户表查询用户信息select u.username,u.user_img,c.* from product_comments cinner join users u on c.user_id=u.user_idwhere c.product_id=3

10.1 新建的VO,ProductCommentsVO (一对一的连表查询可以不用在实体类中声明另一个实体类)

package com.qfedu.fmmall.entity;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import javax.persistence.Column;import javax.persistence.Table;import java.util.Date;@Data@AllArgsConstructor@NoArgsConstructorpublic class ProductCommentsVO {    private Integer productId;    private String productName;    private Integer orderItemId;    private String isannonymouns;    private Integer commType;    private Integer commLevel;    private String commImgs;    private String sepcName;    private Integer replyStatus;    private String replyContent;    private Date replyTime;    private Integer isShow;//用于封装评论对应的用户数据    private Integer userId;    private String username;    private String nickname;    private String userImg;}

在Mapper定义相应的接口:

package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.ProductComments;import com.qfedu.fmmall.entity.ProductCommentsVO;import com.qfedu.fmmall.general.GeneralDao;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface ProductCommentsMapper extends GeneralDao {    public List selectCommentsByProductId(int productId);}

十一、添加购物车的功能实现10.1流程分析:

点击添加购物车———商品、选择套餐id,套餐属性,数量,token————-进行token的校验

10.2数据库的相关的操作

  1. 增加字段sku_props

    表生成之后 用逆向工程重新生成shopping_cart表的相关的结构。修改generalConfig.xml把%修改成shopping_cart

    注意一下%表示生成所有的表

10.2.1 购买的数量的前端实现在vue的methods中添加+和-的点击事件

changeNum:function(m){if(m==-1 && this.num>1){this.num=this.num-1;}else if(m==1 && this.num<this.productSkus[this.currentSkuIndex].stock){this.num=parseInt(this.num)   +1;}},

进行商品数量的绑定可以用 v-model=”num”进行双向绑定

库存{{productSkus[currentSkuIndex].stock}}

10.2.2给加入购物车这个按钮添加点击事件

  • 把相关的添加的购物车的信息放入cart这个类中:

    addShopCart(){var uid=getCookieValue("userId");var propStr="";// 套餐属性转换成字符串for(var key in this.chooseskuProps){propStr+=key+":"+this.chooseskuProps[key]+";";}var cart={"cartNum": this.num,"cartTime": "","productId": this.productId,"productPrice": this.productSkus[this.currentSkuIndex].sellPrice,"skuId": this.productSkus.skuId,"skuProps":propStr,"userId": uid};//从cookie中获取tokenvar token=getCookieValue("token");console.log("---token-------");console.log(token);// 把购物车的信息放入数据库中var url5=baesUrl+"shopcart/add";axios.post({url:url5,methods:"post",headers:{token:token},data:cart}).then( res=>{console.log("------res-----"+res);}); }

    十二、添加购物车时候用户未登录12.1 添加购物车用户未登录,业务处理方式:

    1. 查询商品详情页面的时候,就提示先登录,跳转到登录页面
    2. 当点击添加购物车,弹窗显示先登录,完成登录,点击添加购物车
    3. 点击添加购物车,会跳转到登录页面,登录完成之后会跳转到商品详情页面。

    12.2我们使用第三种难度最大的来12.3使用Layui进行添加购物车成功/失败的提示

    • 引入lay-ui cdn

             

      12.3.1声明layui的弹窗组件12.3.2成功失败进行提示

    十三购物车的列表

    流程图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NmuB7noP-1633446686643)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210922164854113.png)]

    步骤

    1. 获取用户user_id
    2. 通过user_id获取购物车的信息(包括商品的名字,商品图片的信息)
    3. 将购物车信息数据返回给前端 。
    4. 也就是有三张表,购物车表(shopping_cart),商品表(product),商品图片表(product_img 根据商品id查询商品主图)

    13.1数据库dao接口的实现

    1. sql语句

      select  c.*,p.product_name,i.url from shopping_cart cinner join product pinner join product_img ion c.product_id=p.product_id and i.item_id=p.product_idwhere user_id=2 and i.is_main=1;
       2. dao接口  ```java    List  selectShoppingCartByUserId(int userid);

    13.2pojo接口实现

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HvWCzaRC-1633446686643)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210922172106911.png)]

    注意一下数据库的shopping_cart表不需要加上这两个字段,是通过product_img表和product表的column属性来进行关联的

    13.3修改购物车13.31通过这个进行购物车数量的修改:13.32changNum函数进行实现:

               methods:{   changeNum(event){   var oper=event.srcElement.dataset.oper;   var index=event.srcElement.dataset.id;   console.log(oper);   if(oper=="+"){  this.shoppingCartsSC[index].cartNum=parseInt(this.shoppingCartsSC[index].cartNum) +1;      }else{if(this.shoppingCartsSC[index].cartNum>1){this.shoppingCartsSC[index].cartNum=parseInt(this.shoppingCartsSC[index].cartNum)-1;  }   }   //   修改的cartId和cartNumvar cartId=this.shoppingCartsSC[index].cartId;var cartNum=this.shoppingCartsSC[index].cartNum;var url1=baseUrl+"shopcart/update/"+cartId+"/"+cartNum;axios({url:url1,method:"put",params:{token:this.token}}).then((res)=>{console.log(res);})   },// addNum:function(event){// // 这个可以打印绑定的id的值// console.log("--add"+event.srcElement.dataset.id);//     var index=event.srcElement.dataset.id;// this.shoppingCartsSC[index].cartNum=parseInt(this.shoppingCartsSC[index].cartNum) +1;// },// mulNum:function(event){//     var index=event.srcElement.dataset.id;// if(this.shoppingCartsSC[index].cartNum>1){// this.shoppingCartsSC[index].cartNum=parseInt(this.shoppingCartsSC[index].cartNum)-1;//   }// }   }

    十四购物车提交订单结算功能实现14.1实现流程分析

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r7eZLbEB-1633446686645)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210924214722021.png)]

    十五、订单提交及支付流程15.1流程分析

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v5zo96Td-1633446686646)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210926112259576.png)]

    15.2订单添加接口实现15.3数据库操作

    • 根据收货id获取收货的地址信息(tkmapper)
    • 根据购物车ID,查询购物车详情(需要关联查询商品名称,sku名称,库存,商品图片,商品价格)—-》 获取生成商品快照的数据 只需在ShoppingCartVO中多加上一个stock字段就好,然后在ShoppCartMapper.xml加上需要查询的这个字段
    • 保存订单信息(tkMapper)
    • 修改库存(tkMapper)
    • 保存商品快照(tkMapper)

    15.4serviceimpl层实现 注意:这个方法需要加上@Transactional,也就是订单生成的时候,快照也必须生成

    1. 生成OrderId的方法 UUID.random().toString()
    2. 通过时间戳生成System.currentTimeMillis()+(new Random().nextInt(9999)+100)+””
    package com.qfedu.fmmall.service.impl;import com.qfedu.fmmall.dao.OrdersItemMapper;import com.qfedu.fmmall.dao.OrdersMapper;import com.qfedu.fmmall.dao.ProductSkuMapper;import com.qfedu.fmmall.dao.ShoppingCartMapper;import com.qfedu.fmmall.entity.Orders;import com.qfedu.fmmall.entity.OrdersItem;import com.qfedu.fmmall.entity.ProductSku;import com.qfedu.fmmall.entity.ShoppingCartVO;import com.qfedu.fmmall.service.OrderService;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Transactional;import tk.mybatis.mapper.entity.Example;import java.math.BigDecimal;import java.math.BigInteger;import java.sql.SQLException;import java.util.*;import static java.math.BigDecimal.*;@Servicepublic class OrderServiceimpl implements OrderService{    @Autowired    private ShoppingCartMapper shoppingCartMapper;    @Autowired    private OrdersMapper ordersMapper;    @Autowired    private OrdersItemMapper ordersItemMapper;    @Autowired    private ProductSkuMapper productSkuMapper;    /* userId 1(zhangsan) 3(houzhicong)    *cids  "39,40,41"    * @return    *    * *///    int userId, String receiverName,//    String receiverMobile,String address,//    double price,int payType,String orderRemark   把这些用Orders对象来接收//    保存订单的步骤//    1.查询选中购买的购物车详情//    2. 校验库存//    3.保存订单//    4.保存订单快照//    5.购买成功需要删除购物车记录//    可以知道这四个步骤需要同时成功或者同时失败,符合一个事务的操作(ACID)    @Transactional    public Map addOrder(List cids, Orders orders) throws  SQLException{         Map map=new HashMap();//        根据cids查询购物车的详情记录(包括库存)        List shoppingCartVOList = shoppingCartMapper.selectShoppingcartByids(cids);//        校验库存        boolean f=true;        String untitled="";        for (ShoppingCartVO sc :shoppingCartVOList                ) {            if(Integer.valueOf(sc.getCartNum())>sc.getStock()){                f=false;            }//            获取所有的商品名称,以,分割拼接成字符串            untitled=untitled+sc.getProductName()+",";        }        if(f){//            表示库存充足进行保存//            1.userId  2 untitled名称 3 收件人地址,姓名,电话,地址//            4. 总价格 5.支付方式//            6.创建 订单的时间//            7.订单初始状态 1 待支付        orders.setStatus(1);        orders.setUntitled(untitled);        orders.setCreateTime(new Date());        orders.setCancelTime(new Date());        orders.setDeliveryTime(new Date());//        生成订单编号            String orderId = UUID.randomUUID().toString().replace("-", "");            orders.setOrderId(orderId);//            保存订单            int i=ordersMapper.insert(orders);            if(i>0){//               ordersItem 生成商品快照//                List ordersItemList=new ArrayList();                for (ShoppingCartVO sc :shoppingCartVOList) {//                    生成订单的编号                    int cnum=Integer.valueOf(sc.getCartNum());                  String itemid=System.currentTimeMillis()+(new Random().nextInt(9999)+100)+"";                    String itemid1 = itemid.substring(1, 10);//                 注意一下double需要转换为Bigdecimal类型//                public OrdersItem(Integer orderId, Integer productId,//                String productName,//                String productImg, Integer skuId, String skuName,//                BigDecimal productPrice, Integer buyCounts,//                BigDecimal totalAmount, Date basketDate, Date buyTime,//                Integer isComment)                int itemid2=Integer.parseInt(itemid1);                OrdersItem ordersItem=  new OrdersItem();                ordersItem.setOrderId(itemid2);                ordersItem.setProductId(Integer.valueOf(sc.getProductId()));                ordersItem.setProductName(sc.getProductName());                ordersItem.setProductImg(sc.getProductImg());                ordersItem.setSkuId(Integer.valueOf(sc.getSkuId()));                    System.out.println(sc.getSkuName());                    ordersItem.setSkuName(sc.getSkuName());                System.out.println(sc.getSellPrice());                ordersItem.setProductPrice(new BigDecimal(String.valueOf(sc.getProductPrice())));                ordersItem.setBuyCounts(cnum);                ordersItem.setTotalAmount(sc.getProductPrice());                ordersItem.setBasketDate(new Date());                ordersItem.setBuyTime(new Date());                ordersItem.setIsComment(0);//                ordersItemList.add(ordersItem);                      int m=ordersItemMapper.insert(ordersItem);                    }//                int j = ordersItemMapper.insertList(ordersItemList);//  扣减库存???//                根据套餐Id修改库存量                for (ShoppingCartVO sc :shoppingCartVOList                ) {                    String skuId = sc.getSkuId();                    int newStock=sc.getStock()-Integer.valueOf(sc.getCartNum());//                    Example example = new Example(ProductSku.class);//                    Example.Criteria criteria = example.createCriteria();//                    criteria.andEqualTo("skuId",skuId);//                    ProductSku productSku = productSkuMapper.selectByPrimaryKey(skuId);                    ProductSku productSku=new ProductSku();                    productSku.setSkuId(skuId);                    productSku.setStock(String.valueOf(newStock));//                    productSku.setSkuImg(null);                    productSkuMapper.updateByPrimaryKeySelective(productSku);                }//  保存订单成功 删除购物车记录                for (Integer cid:cids                     ) {                    shoppingCartMapper.deleteByPrimaryKey(cid);                }                 map.put("orderId",orderId);                 map.put("productNames",untitled);              return   map;            }        }else{//            不足   return null;        }        return null;    }}

    swagger报错解决

    For input String :””

    在application.yml加上日志的配置:

    logging:  level:    io.swagger.models.parameters.AbstractSerializableParameter: error

    十六 商品个人中心订单信息的查询16.1 流程分析

    1. 根据用户id进行订单信息的查询
    2. 可以关联进行查询订单快照

    sql语句

                select o.order_id,        o.user_id,        o.untitled,        o.receiver_name,        o.receiver_mobile,        o.receiver_address,        o.total_amount,        o.actual_amount,        o.pay_type,        o.order_remark,        o.status,        o.delivery_type,        o.delivery_flow_id,        o.order_freight,        o.delete_status,        o.create_time,        o.update_time,        o.pay_time,        o.delivery_time,        o.finish_time,        o.cancel_time,        o.close_type        from orders o        where o.user_id=#{userId}                    and o.status=#{status}                limit #{start},#{limit}    

    OrderMapper.xml文件:

                                                                                                                                                                                                                        select o.order_id,        o.user_id,        o.untitled,        o.receiver_name,        o.receiver_mobile,        o.receiver_address,        o.total_amount,        o.actual_amount,        o.pay_type,        o.order_remark,        o.status,        o.delivery_type,        o.delivery_flow_id,        o.order_freight,        o.delete_status,        o.create_time,        o.update_time,        o.pay_time,        o.delivery_time,        o.finish_time,        o.cancel_time,        o.close_type        from orders o        where o.user_id=#{userId}                    and o.status=#{status}                limit #{start},#{limit}    

    16.2 接口开发

    package com.qfedu.fmmall.dao;import com.qfedu.fmmall.entity.Orders;import com.qfedu.fmmall.entity.OrdersVO;import com.qfedu.fmmall.general.GeneralDao;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Repository;import java.util.List;@Repositorypublic interface OrdersMapper extends GeneralDao {    List selectOrders(@Param("userId") String userId,                               @Param("status") String status,                                @Param("start")int start,                                @Param("limit")int limit);}

    16.2.1 Service层接口开发

      @Override    public ResultVO selectOrders(String userId, String status, int pageNum, int limit) {   int start=(pageNum-1)*limit;        List ordersVOS = ordersMapper.selectOrders(userId, status, pageNum, limit);//   2.查询总记录数        Example example = new Example(Orders.class);        Example.Criteria criteria = example.createCriteria();        criteria.andLike("userId",userId);        if(status!=null&&!"".equals(status)){            criteria.andLike("status",status);        }//        2.查询总记录数        int count=ordersMapper.selectCountByExample(example);//        查询总页数        int pageCount=count%limit==0?count/limit:count/limit+1;//        3.封装数据        PageHelper ordersVOPageHelper = new PageHelper(count, pageCount, ordersVOS);        return new ResultVO(ResultStatus.OK,"订单查询成功",ordersVOPageHelper);    }

    16.2.2 Controller层实现

    package com.qfedu.fmmall.controller;import com.github.wxpay.sdk.WXPay;import com.qfedu.fmmall.config.MyPayConfig;import com.qfedu.fmmall.entity.Orders;import com.qfedu.fmmall.service.OrderService;import com.qfedu.fmmall.vo.ResultStatus;import com.qfedu.fmmall.vo.ResultVO;import io.swagger.annotations.Api;import io.swagger.annotations.ApiImplicitParam;import io.swagger.annotations.ApiImplicitParams;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.sql.SQLException;import java.util.HashMap;import java.util.List;import java.util.Map;@RestController@CrossOrigin@RequestMapping("/order")@Api(value = "提供订单相关的接口",tags = "订单管理")public class OrderController {    @Autowired    private OrderService orderService;    @PostMapping("/add/{cids}")    public ResultVO add(@PathVariable("cids") List cids,                        @RequestBody Orders orders){        ResultVO resultVO=null;//        测试用的OrderId        try {            Map orderInfo = orderService.addOrder(cids, orders);            String orderId=orderInfo.get("orderId");//           订单快照创建成功,申请支付链接            HashMap data=new HashMap();//            设置当前订单信息            data.put("body",orderInfo.get("productNames")); //商品描述            data.put("out_trade_no",orderId);//使用当前用户订单编号作为当前支付交易的交易编号            data.put("fee_type","CNY"); //支付币种            data.put("total_fee", orders.getActualAmount()+""); //支付金额            data.put("trade_type","NATIVE");//交易类型//            必填选项   用于设置支付完成时的回调方法接口            data.put("notify_url","/pay/success");            WXPay wxPay=new WXPay(new MyPayConfig());            Map resp = wxPay.unifiedOrder(data);//            把微信支付平台生成的链接获取到            orderInfo.put("payUrl",resp.get("code_url"));            resultVO=new ResultVO(ResultStatus.OK,"提交订单成功!",orderInfo);            System.out.println(resp);//            code_url -> weixin://wxpay/bizpayurl?pr=Iv5Fsq6zz        } catch (SQLException e) {            resultVO= new ResultVO(ResultStatus.NO,"下单失败",null);        } catch (Exception e) {            e.printStackTrace();        }        return resultVO;    }//    订单分页查询@RequestMapping(value = "/list",method = RequestMethod.GET)@ApiImplicitParams({        @ApiImplicitParam(dataType = "string",name = "userId",value = "用户Id",required = true),        @ApiImplicitParam(dataType = "string",name = "status",value = "订单状态",required = false),        @ApiImplicitParam(dataType = "int",name = "pageNum",value = "当前页数",required = true),        @ApiImplicitParam(dataType = "int",name = "limit",value = "页数大小",required = false),})public ResultVO selectOrders(@RequestHeader("token")String token, String userId, String status, int pageNum, int limit) {    ResultVO resultVO = orderService.selectOrders(userId, status, pageNum, limit);    return  resultVO; }}

    16.2.3前端使用Vue+ElementUI实现分页功能1. 引入cdn

       

    2. data中定义相关数据

    var baseUrl="http://localhost:8080/";      var vm=new Vue({el:"#app",data:{token:"",username:"",pageNum:1,limit:6,userId:"",orders:[],count:0,status:null,},created(){ this.token=getCookieValue("token"); this.userId=getCookieValue("userId"); this.username=getCookieValue("username");//  加载页面,请求订单信息var url1=baseUrl+"order/list";axios({url:url1,method:"get",headers:{token:this.token},params:{userId:this.userId,pageNum:this.pageNum,limit:this.limit}}).then((res)=>{console.log(res.data);if(res.data.code==1){this.orders=res.data.data.data;console.log(this.orders);this.count=res.data.data.count;}});},methods: {// 通过订单状态进行查询queryByStatus(status){this.status=status;console.log(this.status);// 重新按照状态查询一次//  加载页面,请求订单信息var url1=baseUrl+"order/list";axios({url:url1,method:"get",headers:{token:this.token},params:{userId:this.userId,pageNum:this.pageNum,limit:this.limit,status:this.status}}).then((res)=>{console.log(res.data);if(res.data.code==1){this.orders=res.data.data.data;console.log(this.orders);this.count=res.data.data.count;}});},gotoComment:function(event){var index=event.srcElement.dataset.index;console.log(index);var order=this.orders[index];localStorage.setItem("order",JSON.stringify(order));location.href="user-comment.html";}}, })

    3.分页的相关的方法

    // 通过分页进行查询pager(page){this.pageNum=page;//重新加载页面//  加载页面,请求订单信息// -------------分页查询按照状态进行查询var obj={userId:this.userId,pageNum:this.pageNum,limit:this.limit};if(this.status!=null){obj.status=this.status;}// ------------var url1=baseUrl+"order/list";axios({url:url1,method:"get",headers:{token:this.token},params:obj}).then((res)=>{console.log(res.data);if(res.data.code==1){this.orders=res.data.data.data;console.log(this.orders);this.count=res.data.data.count;}});},

    4. 分页的表格

    序号订单商品订单状态时间操作
    {{index+1}}{{order.untitled}}待付款待发货待收货待评价已完成已关闭{{order.createTime}}

    Linux的常用 的命令的复习

    linux中没有盘符,根路径用 “/”表示

    rm -rf 你的目录的名字

    linux的系统结构和相关的目录结构

    bin,sbin(超级管理员的命令目录),etc(系统配置文件),lib/lib4(系统所需的依赖库),boot(系统启动的相关的文件),

    目录说明
    bin系统文件
    sbin超级管理员系统命令
    boot系统启动相关的目录
    etc系统配置文件
    lib/lib4存放系统所需的依赖库
    home一般用户所在的文件夹
    root超级管理员目录(root用户目录)
    media媒体(光驱)
    mnt挂载(u盘,移动硬盘)
    tmp/opt临时的文件存储目录,比如日志在tmp或者opt目录下面
    usr用户目录,我们通常安装的软件,用户的一些文件都在此目录下面
    run srv sys var proc dev系统相关目录

    ls -a #可以显示隐藏文件

    Linux系统安装jdk

    1. 通过SecureFx上传你的linux版本的jdk

    2. 进行解压tar -zxcf 你的压缩包的名字

    3. 在/etc/profile目录进行环境变量的配置。

      加上如下的配置:

      #JAVA_HOMEexport JAVA_HOME=/opt/module/jdk1.8.0_144export PATH=$PATH:$JAVA_HOME/bin

    Linux安装Tomcat

    1. 通过Secure在windows中上传你的Tomcat包,

    2. 进行解压到指定的目录

    3. 在它的bin目录下面进行启动

      ./startup.sh
    4. 不使用了可以关闭tomcat

      lsof -i:8080kill -9 PID

      如果你的项目是部署在Tomcat上面的,你可以把你的项目打成war包,放在tomcat的weapp目录下面,运行tomcat即可进行该项目

    Linux安装mysql(在线安装)

    通过如下的指定进行安装:

    wget http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm

    然后使用下面指定(如果没有权限需要su root):

     rpm -ivh mysql57-community-release-el7-10.noarch.rpm 

    正式安装mysql服务:

    yum -y install mysql-community-server

    报错:

    Error: Package: mysql-community-server-5.7.36-1.el7.x86_64 (mysql57-community)
    Requires: systemd

    使用命令看你是否安装了MySQL

    rpm -qa|grep -i mysql

    已经安装好的mysql加入开机启动

    systemctl enable mysqld

    进行启动mysql服务:

    systemctl start mysqld

    20.锋迷项目的后端云部署20.1企业项目当中需要进行修改的东西:

    1. application.yml文件中需要改变连接的url;改成你的数据库的服务器的ip地址,比如localhost变为你的ip地址
    2. 如果你有微信支付的回调接口data.put("notify_url","/pay/success");,变成你的云主机的地址。

    Maven中先进行clean,然后进行package进行打包的操作,在api中找到你的打包的jar包进行。

    20.11在你的Linux中建立一个目录用来存放你的jar包:

    运行这个命令进行运行你的项目:

     java -jar api-2.0.1.jar

    api-2.0.1.jar为你的jar包的名字。

    如果报错: no main manifest attribute, in api-2.0.1.jar

    可以在你的pom.xml文件中加上这个配置(在dependencies下面):

                                         org.springframework.boot                spring-boot-maven-plugin                2.0.1.RELEASE                                    com.qfedu.fmmall.ApiApplication                                                                                                        repackage                                                                                    

    然后再次运行上面的命令:java -jar 你的jar包名字。

    启动成功如图所示:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gmOreCEF-1640608196271)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20211226182330211.png)]

    这样当你ctrl+c你的服务就会停止。

    使用这个指令可以使你的服务一直开着:

    java -jar api-2.0.1.jar &

    注意一下:你的依赖的引入不可以重复

    21.前端的项目的部署在云服务器上面

    我们的云主机有安装Tomcat,可以部署在Tomcat上面:

    由于上面的Tomcat8080已经启动了,我们可以修改一下它的conf目录下面的server.xml文件:

    cd /opt/module/apache-tomcat-8.5.73/cd conf#可以查出8080在server.xml的哪行cat -n server.xml |grep 8080#可以在server.xml中编辑69行vim +69 server.xml

    1. 修改所有的请求的localhost地址为你的云服务器的地址

    2.上传Tomcat到你的Linux的服务器中,进行解压

    3.把你的前端的项目从windows中上传到Linux的Tomcat的webapp目录下面。

    4.到bin目录下面进行启动命令为:

    ./startup.sh

    5.通过路径进行访问你的前端的项目。

    #可以查看你的Linux的服务器的ipifconfig#路径在加上你的Tomcat的端口号9999http://192.168.48.5:9999/fmall-static/index.html

    访问成功的截图:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xuUhtOgj-1640608196273)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20211227092944455.png)]

    Tomcat作为前端项目的弊端1.前端会有大量的请求,Tomcat的弊端(难以满足高并发的,大约是2000-3000,使用Niginx可以提高高并发的承受,大约2万)

    1. Tomcat的核心价值在于能够便于执行java程序,而不是处理并发
    2. 结论:tomcat不适合部署前端项目

    22.Nginx

    它是一个高性能的Http和反向代理web服务器

    • Nginx是基于http协议的请求和响应(部署web项目) —静态资源
    • 可以作为反向代理服务器 —-负载均衡(代理服务器)

    高性能体现:

    1. 稳定性好,可以7*24不间断的运行
    2. 配置简洁
    3. 可以承受高并发(5w+)

    23.前端项目部署在Nginx上面

    1. 安装nginx

    2. 将前端项目fmall-static拷贝到nginx的根目录

    3. 修改nginx/conf里面的nginx.conf文件:

      location /{root fmall-static;index index.html index.htm;}

      24.Linux安装Nginx(在线安装)24.1 安装编译工具(nginx安装之前需要编译)

      yum install -y gcc gcc-c++

      24.2安装PCRE

      # 1.下载wget http://downloads.sourceforge.net/project/pcre/pcre/8.35/pcre-8.35.tar.gz# 2.解压tar -zxvf pcre-8.35.tar.gz# 3.进入目录 cd pre-8.35# 4.配置./configure# 5.编译安装make && make install

      24.3安装SSL库

      cd /opt/softwarewget http://www.openssl.org/source/openssl-1.0.1j.tar.gztar -zxvf openssl-1.0.1j.tar.gz# 4.配置./configure# 5.编译安装make && make install

      24.4安装zlib库

      wget http://zlib.net/zlib-1.2.11.tar.gztar -zxvf zlib-1.2.11.tar.gz  -C ../module/cd zlib-1.2.11/./configuremake && make install

      24.5下载Nginx

      可以本地上传或者在线下载

      wget https://nginx.org/download/nginx-1.16.1.tar.gzcd nginx-1.16.1/ ./configure --prefix=nginx-1.16.1/ --with-http_stub_status_module --with-http_ssl_module --with-pcre=../pcre-8.35/ make && make install

      成功:

      Configuration summary

      • using PCRE library: ../../pcre-8.35/
      • using system OpenSSL library
      • using system zlib library

      nginx path prefix: “../../nginx-1.16.1/”
      nginx binary file: “../../nginx-1.16.1//sbin/nginx”
      nginx modules path: “../../nginx-1.16.1//modules”
      nginx configuration prefix: “../../nginx-1.16.1//conf”
      nginx configuration file: “../../nginx-1.16.1//conf/nginx.conf”
      nginx pid file: “../../nginx-1.16.1//logs/nginx.pid”
      nginx error log file: “../../nginx-1.16.1//logs/error.log”
      nginx http access log file: “../../nginx-1.16.1//logs/access.log”
      nginx http client request body temporary files: “client_body_temp”

    然后make && make install以后没有报错出现下面的信息:

    test -d ‘nginx-1.16.1//logs’
    || mkdir -p ‘nginx-1.16.1//logs’
    make[1]: Leaving directory `/opt/module/nginx-1.16.1′

    查看成功的nginx:ll

    [root@hadoop102 nginx-1.16.1]# lltotal 16drwxr-xr-x. 2 root root 4096 Dec 25 07:10 confdrwxr-xr-x. 2 root root 4096 Dec 25 07:10 htmldrwxr-xr-x. 2 root root 4096 Dec 25 07:10 logsdrwxr-xr-x. 2 root root 4096 Dec 25 07:10 sbin

    启动nginx:

    cd /opt/software/nginx-1.16.1/nginx-1.16.1/sbin./nginx

    然后报错:

    ./nginx: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory

    解决办法:

    find / -name *libcrypto*  

    找到这个路径:/usr/local/lib64/libcrypto.so.1.1

    cd /usr/local/lib64/

    查看防火墙的状态和关闭防火墙:

    #查看防火墙状态/etc/init.d/iptables status#关闭防火墙 service iptables stop  #重新启动防火墙 service iptables restart

    报错:

    error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory

    解决:

    ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1