文章目录
- 自己添加的后端管理页面
- 锋迷商城项目
-
- 锋迷商城数据库设计
-
- 2.软件开发步骤
- 3.数据库设计流程
- 3.数据建模工具PDMan
- 4.锋城业务流程设计
- 5接口介绍
- 5.2Swagger(自动生成服务器接口的规范性文档)
- 一、锋迷商城设计及实现用户管理
- 二、逆向工程
- 三、跨域问题
- 四、前端页面的传值
- 五、前后端分离开发用户认证的问题
- 六、JWT(json Web Token)一个别人封装好的工具类生成相关的token
- 6.1生成JWT
- 6.3使用请求头进行传递token
- 七首页的分类列表的的实现
- 八、商品的推荐功能实现
- 8.2.2业务层实现
- 九、商品详情显示(在Introduction.html进行相关的显示)
- 十、显示商品评价的信息(通过用户和商品评论表进行相关的连表查询)
- 十一、添加购物车的功能实现
- 十二、添加购物车时候用户未登录
- 十三购物车的列表
- 十四购物车提交订单结算功能实现
- 十五、订单提交及支付流程
- swagger报错解决
- 十六 商品个人中心订单信息的查询
- 20.锋迷项目的后端云部署
- 21.前端的项目的部署在云服务器上面
- Tomcat作为前端项目的弊端
- 22.Nginx
- 23.前端项目部署在Nginx上面
- 24.Linux安装Nginx(在线安装)
自己添加的后端管理页面
视频演示效果
毕业设计SpringBoot+Vue+ElementUI商城系统实现(有后台)
1. 商品管理
2.商品分类管理
3.商品地址管理
4.用户中心管理
4. 用户权限管理
5.订单管理
6.商品品牌管理
锋迷商城项目
使用Maven聚合项目进行创建(一个maven的父项目多个maven的子项目),
可以在父项目pom.xml文件中加上:
<package>pom<package>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aKHt478Q-1633568521449)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210812151308862.png)]
1.通过Maven聚合工程搭建项目:
1. 创建一个Maven的父项目,然后修改它的pom.xml文件,可以删除src等一些没有用的目录
<packaging>pom<packaing>
2.在父项目下面创建多个module,包括(common,beans,mapper,service,api)把它们全部打包成jar包
pom.xml加上
<packaging>jar</packaging>
3.由于mapper层需要调用beans层(pojo),需要在pom.xml文件中,然后可以在mapper中加入相关的依赖。
<dependencies>
<!-- mapper需要用到Beans所以需要加上beans的依赖-->
<dependency>
<groupId>org.example</groupId>
<artifactId>beans</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
4.创建service需要调用mapper,和common,需要在pom.xml文件中加上
<dependency>
<groupId>org.example</groupId>
<artifactId>mapper</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>org.example</groupId>
<artifactId>common</artifactId>
<version>2.0.1</version>
</dependency>
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引入相关的依赖:
<!-- swagger2接口文档生成工具-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- swagger-ui-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
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 {
/*
* 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加入依赖
<!-- swagger-ui插件-->
<!-- https://mvnrepository.com/artifact/com.github.xiaoymin/swagger-bootstrap-ui -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
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
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qfedu.fmmall.dao.UserDao">
<resultMap id="userResultMap" type="User">
<id column="user_id" property="userId"></id>
<result column="username" property="userName"/>
<result column="password" property="password"/>
<result column="nickname" property="nickname"/>
<result column="realname" property="realname"/>
<result column="user_img" property="userImg"/>
<result column="user_mobile " property="userMobile"/>
<result column=" user_email" property="userEmail"/>
<result column="user_sex " property="userSex"></result>
<result column=" user_birth" property="userBirth"></result>
<result column="user_regtime " property="userRegtime"></result>
<result column="user_modtime " property="userModtime"></result>
</resultMap>
<select id="queryByName" resultType="User">
select *from users where username=#{username}
</select>
<insert id="insert" parameterType="User">
insert into users(username,password,user_regtime,user_modtime) values (#{username},
#{password},#{userRegtime},#{userModtime})
</insert>
</mapper>
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插件
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
7.1逆向工程配置
在resources的generator目录下面创建generatorConfig.xml
-
需要修改数据库的配置
-
需要修改pojo,mapper,Mapper.xml文件生成位置的配置
-
<!--%表示当前这个数据库里面的所有的表都会被生成--> <table tableName="%"></table>
-
<!-- 指定生成 Mapper 的继承模板 --> <plugin type="tk.mybatis.mapper.generator.MapperPlugin"> <property name="mappers" value="com.hou.general.GeneralDao"/> </plugin>
-
指定你的用Configuration generatorConfig.xml文件的路径
-
注意一下你的文件一定想要有空格什么东西的
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- 引入 application.properties -->
<!-- <properties resource="application.properties" />-->
<!-- MyBatis3Simple:不生成 Example相关类及方法 defaultModelType="flat" -->
<context id="MysqlContext" targetRuntime="MyBatis3Simple" >
<property name="beginningDelimiter" value="`"/>
<property name="endingDelimiter" value="`"/>
<!-- 指定生成 Mapper 的继承模板 -->
<plugin type="tk.mybatis.mapper.generator.MapperPlugin">
<property name="mappers" value="com.qfedu.fmmall.general.GeneralDao"/>
</plugin>
<!--注意context内的文件要按序放-->
<commentGenerator>
<property name="suppressDate" value="true"/>
<!-- 是否去除自动生成的注释 true:是 : false:否 -->
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!-- jdbc 连接配置 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/fmmall?characterEncoding=utf8"
userId="root"
password="roothouzhicong">
</jdbcConnection>
<javaTypeResolver>
<!-- 是否使用bigDecimal, false可自动转化以下类型(Long, Integer, Short, etc.) -->
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- 生成实体类的包名和位置 ,targetPackage指的是包名,targetProject值得是路径位置-->
<!-- 对于生成的pojo所在包,pojo其实就是domain Entity-->
<javaModelGenerator targetPackage="com.qfedu.fmmall.entity" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<!-- 对于生成的mapper.xml所在目录 -->
<sqlMapGenerator targetPackage="/" targetProject="src/main/resources/mappers"/>
<!-- 配置mapper对应的java映射 也可以叫dao层 -->
<javaClientGenerator targetPackage="com.qfedu.fmmall.dao" targetProject="src/main/java"
type="XMLMAPPER"/>
<!--%表示当前这个数据库里面的所有的表都会被继承-->
<table tableName="%"></table>
</context>
</generatorConfiguration>
7.2在pom.xml文件中指定generatorConfig.xml文件的路径
加上了这个:
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
</configuration>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>1.3.5</version>
<configuration>
<configurationFile>${basedir}/src/main/resources/generator/generatorConfig.xml</configurationFile>
</configuration>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.46</version>
</dependency>
<dependency>
<groupId>tk.mybatis