栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

学习锋迷商城的的笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

学习锋迷商城的的笔记

文章目录
    • 锋迷商城项目
      • 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 流程分析
      • 16.2 接口开发
        • 16.2.1根据类别查询商品接口

锋迷商城项目

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

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

pom

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NA1kXE9E-1633446686620)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-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:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-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

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

    购物车的设计:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xztkvKoC-1633446686626)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210814213038578.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AxMTDyIv-1633446686628)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210814215338098.png)]

4.锋城业务流程设计

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BGyg8OoE-1633446686629)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210814230313101.png)]

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

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

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

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-96PeIJ8O-1633446686630)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210814230815317.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G0wixnwP-1633446686631)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210815101028557.png)]

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TPnNWduu-1633446686631)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210815102516744.png)]

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
@EnableSwagger2
public class SwaggerConfig {
    
    @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")请求之上,用来修饰方法和方法中的参数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcmsSUB7-1633446686632)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210815170433850.png)]

 @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;

@Repository
public interface UserDao {

//    用户注册
    public int insert(User user);

//   根据用户名进行登录的验证
    public User queryByName(String name);


}


2.UserMapper.xml




 
  

 
 
 
 
 
 
 
 
     
     
     

 

    
    
							

前端使用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

A页面设置值:

function(res){
	  console.log(res);
	  if(res.code==1000){
// 获取前端传过来的数据 data
		var 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.length<6 ||vm.username.length>20){
                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.length<6 ||vm.password.length>16){
				vm.tips="密码长度为6-16";
                this.colorStyle="color:red";

			}else{
				vm.tips=" ";
				vm.isRight=true;
			}



			}





         }







	}


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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DWoelSut-1633446686634)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210823080556194.png)]

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

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

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

  1. 用户登录将信息存放在session中
  2. 根据session中是否有用户信息来判断用户是否可以进行登录。
5.2前后端分离项目中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w4niCSzY-1633446686635)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210823082009032.png)]

可以知道使用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.*;



@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:

	

登录进行来可以把购物车获取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结构:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LzVJMRUZ-1633446686636)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210823140849801.png)]

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进行解析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;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Autowired
    private CheckTokenInterceptor checkTokenInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CheckTokenInterceptor())
                .addPathPatterns("
    @Id
    @Column(name = "product_id")
    private Integer productId;

    
    @Column(name = "product_name")
    private String productName;

    
    @Column(name = "category_id")
    private Integer categoryId;

    
    @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 +
                '}';
    }

    
    public Integer getProductId() {
        return productId;
    }

    
    public void setProductId(Integer productId) {
        this.productId = productId;
    }

    
    public String getProductName() {
        return productName;
    }

    
    public void setProductName(String productName) {
        this.productName = productName == null ? null : productName.trim();
    }

    
    public Integer getCategoryId() {
        return categoryId;
    }

    
    public void setCategoryId(Integer categoryId) {
        this.categoryId = categoryId;
    }

    
    public Integer getRootCategoryId() {
        return rootCategoryId;
    }

    
    public void setRootCategoryId(Integer rootCategoryId) {
        this.rootCategoryId = rootCategoryId;
    }

    
    public Integer getSoldNum() {
        return soldNum;
    }

    
    public void setSoldNum(Integer soldNum) {
        this.soldNum = soldNum;
    }

    
    public Integer getProductStatus() {
        return productStatus;
    }

    
    public void setProductStatus(Integer productStatus) {
        this.productStatus = productStatus;
    }

    
    public String getContent() {
        return content;
    }

    
    public void setContent(String content) {
        this.content = content == null ? null : content.trim();
    }

    
    public Date getCreateTime() {
        return createTime;
    }

    
    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    
    public Date getUpdateTime() {
        return 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文件实现

注意一下子查询 的语句:

 



  
    
    
    
    
    
    
    
    
    
    
  

  
    
    
    
    
    
    
    
    
    
    
    
  


  
															
															
															库存{{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中获取token
    
    						var 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我们使用第三种难度最大的来

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YQQLuRrZ-1633446686641)(C:UsersCourageAndLoveAppDataRoamingTyporatypora-user-imagesimage-20210920173405055.png)]

    12.3使用Layui进行添加购物车成功/失败的提示
    • 引入lay-ui cdn