畢業設計學習鋒迷商城的的筆記(手寫後台商品管理,分類管理,用戶,地址管理系統)
@
- 自己添加的後端管理頁面
- 鋒迷商城項目
- 鋒迷商城資料庫設計
- 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(在線安裝)
自己添加的後端管理頁面
影片演示效果
[video(video-CZIQF8d5-1652505187791)(type-bilibili)(url-//player.bilibili.com/player.html?aid=641370075)(image-//img-blog.csdnimg.cn/img_convert/6fc48aff3f62b207e20ca7badb21395a.png)(title-畢業設計SpringBoot+Vue+ElementUI商城系統實現(有後台))]論文地址
後台程式碼影片實現講解思路
[video(video-zgz2Gybc-1667056389114)(type-bilibili)(url-//player.bilibili.com/player.html?aid=816242633)(image-//img-blog.csdnimg.cn/img_convert/69a030b2c0a14349f093065947c707ae.jpeg)(title-畢業設計鋒迷商城手敲後台管理,實現邏輯講解,程式碼講解)]1. 商品管理
2.商品分類管理
3.商品地址管理
4.用戶中心管理
4. 用戶許可權管理
5.訂單管理
5.1
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","[email protected]"));
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根據你的配置的埠號進行相關的測試
//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插件-->
<!-- //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.進行訪問,然後可以使用它進行相關的測試
//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"
"//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"
"//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</groupId>
<artifactId>mapper</artifactId>
<version>4.1.5</version>
</dependency>
</dependencies>
</plugin>
三、跨域問題
解決方案:
後端解決辦法:在UserController加上@CrossOrigin註解
前端通過Ajax請求跨域登錄:
<form>
<div class="user-name" style="margin-top: 20px;">
<label for="user"><span class="glyphicon glyphicon-user" aria-hidden="true"></span></label>
<input type="text" name="username" id="userName" placeholder="郵箱/手機/用戶名">
</div>
<div class="user-pass" style="margin-top: 20px;">
<label for="password"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></label>
<input type="password" name="" id="userPwd" placeholder="請輸入密碼">
</div>
</form>
<input type="button" name="" id="submitBtn" value="登 錄" class="am-btn am-btn-primary am-btn-sm">
<script src="static/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
$("#submitBtn").click(function(){
var name=$("#userName").val();
var pwd=$('#userPwd').val();
$.get("//localhost:8080/user/login",{
username:name,
password:pwd,
},function(res){
console.log(res);
},"json"
)
})
</script>
前端使用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){
// 獲取前端傳過來的數據 data
var userInfo=res.data;
// cookie和localstorage可以進行前端的頁面之間的傳值
setCookieValue("username",userInfo.username);
setCookieValue("userImg",userInfo.userImg);
window.location.href="index.html";
}else{
$("#tips").html("<label style='color:red'>"+ res.msg +"</label>");
}
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進行表單的輸入的綁定):
<form>
<div class="user-name" style="margin-top: 20px;">
<label for="user"><span class="glyphicon glyphicon-user" aria-hidden="true"></span></label>
<!-- @keyup進行綁定 -->
<input type="text" name="username" v-model="username" id="userName" @keyup="checkInfo" placeholder="郵箱/手機/用戶名">
</div>
<div class="user-pass" style="margin-top: 20px;">
<label for="password"><span class="glyphicon glyphicon-lock" aria-hidden="true"></span></label>
<input type="password" name="" v-model="password" id="userPwd" placeholder="請輸入密碼"@keyup="checkInfo">
</div>
</form>
五、前後端分離開發用戶認證的問題
5.1單體項目中:
可以知道每台伺服器中存在多個Session,只是id不相同,Cookie中可以存放sessionId,然後判斷是是不是同一個session
在單體項目中用戶怎麼認證的?
在單體項目中視圖資源和控制器都在同一台伺服器,用戶的多次請求老師基於同一個會話,可以基於session進行會話的驗證:
- 用戶登錄將資訊存放在session中
- 根據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> 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> 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:
<script type="text/javascript">
// 進入購物車時要訪問購物車列表的介面shopController介面
var baseUrl="//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);
});
},
})
</script>
登錄進行來可以把購物車獲取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
- 用自定義的token生成的時效性不可以進行定義
- 安全性較差
JWT結構:
6.1生成JWT
-
添加依賴:
<!-- jwt生成 --> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.10.3</version> </dependency> <!-- jjwt生成--> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
UserServiceimpl(登錄成功)生成token:
HashMap<String,Object> 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:
<script type="text/javascript">
// 進入購物車時要訪問購物車列表的介面shopController介面
var baseUrl="//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);
});
},
})
</script>
後端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<Claims> 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使用攔截器進行攔截
- 創建一個CheckTokenInterceptor
- 創建一個攔截器的類 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("/**")
.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;
@Configuration
public 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<Claims> 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 c1
left 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
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=0
select *from category where parent_id=0,
-
創建用於封裝查詢的類別資訊CategoryVO
在Beans模組中entity包下面創建一個CategoryVO實體類用於封裝Category和前端 進行數據的響應,相對於Category多了這個屬性
//實體類中實現當前分類的子分類 private List<CategoryVO> categories; public List<CategoryVO> getCategories() { return categories; } public void setCategories(List<CategoryVO> 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<Category> { //使用連接查詢實現分類列表查詢 public List<CategoryVO> selectAllCategories(); // 子查詢 public List<CategoryVO> selectAllCategories2(int parentId); }
-
映射文件配置
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "//mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.qfedu.fmmall.dao.CategoryMapper"> <resultMap id="BaseResultMap" type="com.qfedu.fmmall.entity.Category"> <!-- WARNING - @mbg.generated --> <id column="category_id" jdbcType="VARCHAR" property="categoryId" /> <result column="category_name" jdbcType="VARCHAR" property="categoryName" /> <result column="category_level" jdbcType="INTEGER" property="categoryLevel" /> <result column="parent_id" jdbcType="INTEGER" property="parentId" /> <result column="category_icon" jdbcType="VARCHAR" property="categoryIcon" /> <result column="category_slogan" jdbcType="VARCHAR" property="categorySlogan" /> <result column="category_bg_color" jdbcType="VARCHAR" property="categoryBgColor" /> </resultMap> <resultMap id="CategoryVoMap" type="com.qfedu.fmmall.entity.CategoryVO"> <!-- WARNING - @mbg.generated --> <id column="category_id1" jdbcType="VARCHAR" property="categoryId" /> <result column="category_name1" jdbcType="VARCHAR" property="categoryName" /> <result column="category_level1" jdbcType="INTEGER" property="categoryLevel" /> <result column="parent_id1" jdbcType="INTEGER" property="parentId" /> <result column="category_icon1" jdbcType="VARCHAR" property="categoryIcon" /> <result column="category_slogan1" jdbcType="VARCHAR" property="categorySlogan" /> <result column="category_bg_color1" jdbcType="VARCHAR" property="categoryBgColor" /> <collection property="categories" ofType="com.qfedu.fmmall.entity.CategoryVO"> <id column="category_id2" jdbcType="VARCHAR" property="categoryId" /> <result column="category_name2" jdbcType="VARCHAR" property="categoryName" /> <result column="category_level2" jdbcType="INTEGER" property="categoryLevel" /> <result column="parent_id2" jdbcType="INTEGER" property="parentId" /> <collection property="categories" ofType="com.qfedu.fmmall.entity.CategoryVO"> <id column="category_id3" jdbcType="VARCHAR" property="categoryId" /> <result column="category_name3" jdbcType="VARCHAR" property="categoryName" /> <result column="category_level3" jdbcType="INTEGER" property="categoryLevel" /> <result column="parent_id3" jdbcType="INTEGER" property="parentId" /> </collection> </collection> </resultMap> <select id="selectAllCategories" resultMap="CategoryVoMap"> 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 c1 left 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 </select>
使用子查詢實現分類列表的查詢:
```xml
<!-- 使用子查詢實現的分類列表查詢-->
<resultMap id="CategoryMap2" type="com.qfedu.fmmall.entity.CategoryVO">
<!--
WARNING - @mbg.generated
-->
<id column="category_id" jdbcType="VARCHAR" property="categoryId" />
<result column="category_name" jdbcType="VARCHAR" property="categoryName" />
<result column="category_level" jdbcType="INTEGER" property="categoryLevel" />
<result column="parent_id" jdbcType="INTEGER" property="parentId" />
<result column="category_icon" jdbcType="VARCHAR" property="categoryIcon" />
<result column="category_slogan" jdbcType="VARCHAR" property="categorySlogan" />
<result column="category_bg_color" jdbcType="VARCHAR" property="categoryBgColor" />
<collection property="categories" column="category_id" select="com.qfedu.fmmall.dao.CategoryMapper.selectAllCategories2"/>
<!-- 這裡的column="category_id"將等於
// 子查詢
public List<CategoryVO> selectAllCategories2(int parentId);裡面的parentId;
-->
</resultMap>
<!-- 使用子查詢實現的分類列表查詢-->
<select id="selectAllCategories2" resultMap="CategoryMap2">
select
category_id,
category_name,
category_level,
parent_id,
category_icon,
category_slogan,
category_pic,
category_bg_color
from category where parent_id=#{parentId};
</select>
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;
@Service
public class CategoryServiceimpl implements CategoryService {
@Resource
private CategoryMapper categoryMapper;
@Override
public ResultVO queryAllCategory() {
List<CategoryVO> 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<ProductImg> imgs; public List<ProductImg> getImgs() { return imgs; } public void setImgs(List<ProductImg> 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<Product> { // 查詢推薦商品資訊 public List<ProductVO> 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<ProductImg> { public List<ProductImg> selectProductImgByProductId(int productId); }
ProductMapper.xml文件實現
注意一下子查詢 的語句:
<collection property="imgs" column="product_id" select="com.qfedu.fmmall.dao.ProductImgMapper.selectProductImgByProductId"></collection>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "//mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.qfedu.fmmall.dao.ProductMapper"> <resultMap id="BaseResultMap" type="com.qfedu.fmmall.entity.Product"> <!-- WARNING - @mbg.generated --> <id column="product_id" jdbcType="INTEGER" property="productId" /> <result column="product_name" jdbcType="VARCHAR" property="productName" /> <result column="category_id" jdbcType="INTEGER" property="categoryId" /> <result column="root_category_id" jdbcType="INTEGER" property="rootCategoryId" /> <result column="sold_num" jdbcType="INTEGER" property="soldNum" /> <result column="product_status" jdbcType="INTEGER" property="productStatus" /> <result column="content" jdbcType="VARCHAR" property="content" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> </resultMap> <resultMap id="ProductVoMap" type="com.qfedu.fmmall.entity.ProductVO"> <!-- WARNING - @mbg.generated --> <id column="product_id" jdbcType="INTEGER" property="productId" /> <result column="product_name" jdbcType="VARCHAR" property="productName" /> <result column="category_id" jdbcType="INTEGER" property="categoryId" /> <result column="root_category_id" jdbcType="INTEGER" property="rootCategoryId" /> <result column="sold_num" jdbcType="INTEGER" property="soldNum" /> <result column="product_status" jdbcType="INTEGER" property="productStatus" /> <result column="content" jdbcType="VARCHAR" property="content" /> <result column="create_time" jdbcType="TIMESTAMP" property="createTime" /> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" /> <collection property="imgs" column="product_id" select="com.qfedu.fmmall.dao.ProductImgMapper.selectProductImgByProductId"></collection> </resultMap> <select id="selectRecommendProducts" resultMap="ProductVoMap"> select product_id, product_name, category_id, root_category_id, sold_num, product_status, content, create_time, update_time from product order by create_time desc limit 0,3; </select> </mapper>
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進行相關的顯示)
點擊商品推薦,商品輪播圖,商品的列表頁面點擊商品,就會進入到商品的詳情頁面。
- 獲取商品id
- 可以查詢商品的詳情資訊(商品的基本資訊,商品套餐,商品圖片資訊。)
- 將商品參數返回給前端
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三張表獲取商品的詳情資訊)
@Repository public interface ProductMapper extends GeneralDao<Product> { // 查詢推薦商品資訊 public List<ProductVO> 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; @Repository public interface ProductImgMapper extends GeneralDao<ProductImg> { public List<ProductImg> 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; @Repository public interface ProductSkuMapper extends GeneralDao<ProductSku> { }
-
業務層實現
//這裡為不需要事務,但是如果某些事務如果調用了我也加入到事務中來
// 事務默認的隔離級別是可重複讀 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<Product> 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<ProductImg> 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<ProductSku> productSkus = productSkuMapper.selectByExample(example2);
// System.out.println(productSkus);
// 把所有的商品的詳情資訊放入HashMap當中進行使用
HashMap<String,Object> 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 c
inner join users u
on c.user_id=u.user_id
where 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
@NoArgsConstructor
public 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;
@Repository
public interface ProductCommentsMapper extends GeneralDao<ProductComments> {
public List<ProductCommentsVO> selectCommentsByProductId(int productId);
}
十一、添加購物車的功能實現
10.1流程分析:
點擊添加購物車———商品、選擇套餐id,套餐屬性,數量,token————-進行token的校驗
10.2資料庫的相關的操作
-
增加欄位sku_props
表生成之後 用逆向工程重新生成shopping_cart表的相關的結構。修改generalConfig.xml,把%修改成shopping_cart
注意一下%表示生成所有的表
<table tableName="shopping_cart"></table>
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”進行雙向綁定
<dd>
<input id="min" class="am-btn am-btn-default" type="button" value="-" @click="changeNum(-1)"/>
<input id="text_box" type="text" v-model="num" style="width:30px;" />
<input id="add" class="am-btn am-btn-default" type="button" value="+" @click="changeNum(1)" />
<span id="stock1" class="tb-hidden">庫存<span class="stock">{{productSkus[currentSkuIndex].stock}}</span>件</span>
</dd>
10.2.2給加入購物車這個按鈕添加點擊事件
<li>
<div class="clearfix tb-btn tb-btn-basket theme-login">
<a id="LikBasket" title="加入購物車" href="" @click="addShopCart()"><i></i>加入購物車</a>
</div>
</li>
把相關的添加的購物車的資訊放入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 添加購物車用戶未登錄,業務處理方式:
- 查詢商品詳情頁面的時候,就提示先登錄,跳轉到登錄頁面
- 當點擊添加購物車,彈窗顯示先登錄,完成登錄,點擊添加購物車
- 點擊添加購物車,會跳轉到登錄頁面,登錄完成之後會跳轉到商品詳情頁面。
12.2我們使用第三種難度最大的來
12.3使用Layui進行添加購物車成功/失敗的提示
-
引入lay-ui cdn
<!-- 引入 layui.css --> <link rel="stylesheet" href="//unpkg.com/[email protected]/dist/css/layui.css"> <!-- 引入 layui.js --> <script src="//unpkg.com/[email protected]/dist/layui.js">
12.3.1聲明layui的彈窗組件
12.3.2成功失敗進行提示
十三購物車的列表
流程圖:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-NmuB7noP-1633446686643)(C:\Users\CourageAndLove\AppData\Roaming\Typora\typora-user-images\image-20210922164854113.png)]
步驟
- 獲取用戶user_id
- 通過user_id獲取購物車的資訊(包括商品的名字,商品圖片的資訊)
- 將購物車資訊數據返回給前端 。
- 也就是有三張表,購物車表(shopping_cart),商品表(product),商品圖片表(product_img 根據商品id查詢商品主圖)
13.1資料庫dao介面的實現
-
sql語句
select c.*,p.product_name,i.url from shopping_cart c inner join product p inner join product_img i on c.product_id=p.product_id and i.item_id=p.product_id where user_id=2 and i.is_main=1;
2. dao介面
```java
List<ShoppingCartVO> 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和cartNum
var 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,也就是訂單生成的時候,快照也必須生成
- 生成OrderId的方法 UUID.random().toString()
- 通過時間戳生成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.*;
@Service
public 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<String,String> addOrder(List<Integer> cids, Orders orders) throws SQLException{
Map<String,String> map=new HashMap<>();
// 根據cids查詢購物車的詳情記錄(包括庫存)
List<ShoppingCartVO> 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<OrdersItem> 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 流程分析
- 根據用戶id進行訂單資訊的查詢
- 可以關聯進行查詢訂單快照
sql語句
<select id="selectOrders" resultMap="OrdertMap1">
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}
<if test="status!=null">
and o.status=#{status}
</if>
limit #{start},#{limit}
</select>
OrderMapper.xml文件:
<resultMap id="OrdertMap1" type="com.qfedu.fmmall.entity.OrdersVO">
<!--
WARNING - @mbg.generated
-->
<result column="order_id" jdbcType="VARCHAR" property="orderId" />
<result column="user_id" jdbcType="VARCHAR" property="userId" />
<result column="untitled" jdbcType="VARCHAR" property="untitled" />
<result column="receiver_name" jdbcType="VARCHAR" property="receiverName" />
<result column="receiver_mobile" jdbcType="VARCHAR" property="receiverMobile" />
<result column="receiver_address" jdbcType="VARCHAR" property="receiverAddress" />
<result column="total_amount" jdbcType="DECIMAL" property="totalAmount" />
<result column="actual_amount" jdbcType="DECIMAL" property="actualAmount" />
<result column="pay_type" jdbcType="VARCHAR" property="payType" />
<result column="order_remark" jdbcType="VARCHAR" property="orderRemark" />
<result column="status" jdbcType="INTEGER" property="status" />
<result column="delivery_type" jdbcType="VARCHAR" property="deliveryType" />
<result column="delivery_flow_id" jdbcType="VARCHAR" property="deliveryFlowId" />
<result column="order_freight" jdbcType="DECIMAL" property="orderFreight" />
<result column="delete_status" jdbcType="INTEGER" property="deleteStatus" />
<result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
<result column="pay_time" jdbcType="TIMESTAMP" property="payTime" />
<result column="delivery_time" jdbcType="TIMESTAMP" property="deliveryTime" />
<result column="finish_time" jdbcType="TIMESTAMP" property="finishTime" />
<result column="cancel_time" jdbcType="TIMESTAMP" property="cancelTime" />
<result column="close_type" jdbcType="INTEGER" property="closeType" />
<!-- 子查詢實現 根據OrdersVO的orderId進行子查詢-->
<collection column="ordersItems" property="order_id" select="com.qfedu.fmmall.dao.OrdersItemMapper.selectOrderItemsByOrderId"/>
</resultMap>
<select id="selectOrders" resultMap="OrdertMap1">
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}
<if test="status!=null">
and o.status=#{status}
</if>
limit #{start},#{limit}
</select>
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;
@Repository
public interface OrdersMapper extends GeneralDao<Orders> {
List<OrdersVO> 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<OrdersVO> 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<OrdersVO> 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<Integer> cids,
@RequestBody Orders orders){
ResultVO resultVO=null;
// 測試用的OrderId
try {
Map<String, String> orderInfo = orderService.addOrder(cids, orders);
String orderId=orderInfo.get("orderId");
// 訂單快照創建成功,申請支付鏈接
HashMap<String,String> 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<String, String> 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
<!-- 引入樣式 -->
<link rel="stylesheet" href="//unpkg.com/element-ui/lib/theme-chalk/index.css">
<script src="static/js/cookie_utils.js"></script>
<!-- element-ui需要引入vue.js -->
<script src="static/js/vue.min.js"></script>
<!-- 引入組件庫 -->
<script src="//unpkg.com/element-ui/lib/index.js"></script>
<script src="static/js/axios.min.js"></script>
<script src="static/js/utils.js"></script>
2. data中定義相關數據
<script type="text/javascript">
var baseUrl="//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";
}
},
})
</script>
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. 分頁的表格
<table class="table">
<tr>
<td>序號</td>
<td>訂單商品</td>
<td>訂單狀態</td>
<td>時間</td>
<td>操作</td>
</tr>
<template v-for="order,index in this.orders">
<tr>
<td>{{index+1}}</td>
<td>{{order.untitled}}</td>
<td>
<span v-if="order.status=='1'">待付款</span>
<span v-else-if="order.status=='2'">待發貨</span>
<span v-else-if="order.status=='3'">待收貨</span>
<span v-else-if="order.status=='4'">待評價</span>
<span v-else-if="order.status=='5'">已完成</span>
<span v-else-if="order.status=='6'">已關閉</span>
</td>
<td>{{order.createTime}}</td>
<td>
<template v-if="order.status=='1'">
<button class="btn btn-success btn-xs">
去支付
</button >
<button class="btn btn-danger btn-xs">
取消訂單
</button>
</template>
<template v-if="order.status=='2'">
<button class="btn btn-danger btn-xs">
取消訂單
</button>
</template>
<template v-if="order.status=='3'">
<button class="btn btn-success btn-xs">
確認收貨
</button >
</template>
<template v-if="order.status=='4'">
<button class="btn btn-success btn-xs" @click="gotoComment" :data-index="index">
去評價
</button >
</template>
<template v-if="order.status=='6'" || v-if="order.status=='5'" >
<button class="btn btn-danger btn-xs">
刪除
</button >
</template>
</td>
</tr>
</template>
<tr>
<td colspan="5">
<!-- 分頁 -->
<el-pagination
background
layout="prev, pager, next"
:current-page="pageNum"
:page-size="limit"
:total="count" @current-change="pager">
</el-pagination>
</td>
</tr>
</table>
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
-
通過SecureFx上傳你的linux版本的jdk
-
進行解壓tar -zxcf 你的壓縮包的名字
-
在/etc/profile目錄進行環境變數的配置。
加上如下的配置:
#JAVA_HOME export JAVA_HOME=/opt/module/jdk1.8.0_144 export PATH=$PATH:$JAVA_HOME/bin
Linux安裝Tomcat
-
通過Secure在windows中上傳你的Tomcat包,
-
進行解壓到指定的目錄
-
在它的bin目錄下面進行啟動
./startup.sh
-
不使用了可以關閉tomcat
lsof -i:8080 kill -9 PID
如果你的項目是部署在Tomcat上面的,你可以把你的項目打成war包,放在tomcat的weapp目錄下面,運行tomcat即可進行該項目
Linux安裝mysql(在線安裝)
通過如下的指定進行安裝:
wget //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企業項目當中需要進行修改的東西:
- application.yml文件中需要改變連接的url;改成你的資料庫的伺服器的ip地址,比如localhost變為你的ip地址
- 如果你有微信支付的回調介面
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下面):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.0.1.RELEASE</version>
<configuration>
<mainClass>com.qfedu.fmmall.ApiApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
然後再次運行上面的命令: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的伺服器的ip
ifconfig
#路徑在加上你的Tomcat的埠號9999
//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萬)
- Tomcat的核心價值在於能夠便於執行java程式,而不是處理並發
- 結論:tomcat不適合部署前端項目
22.Nginx
它是一個高性能的Http和反向代理web伺服器
- Nginx是基於http協議的請求和響應(部署web項目) —靜態資源
- 可以作為反向代理伺服器 —-負載均衡(代理伺服器)
高性能體現:
- 穩定性好,可以7*24不間斷的運行
- 配置簡潔
- 可以承受高並發(5w+)
23.前端項目部署在Nginx上面
-
安裝nginx
-
將前端項目fmall-static拷貝到nginx的根目錄
-
修改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 //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/software wget //www.openssl.org/source/openssl-1.0.1j.tar.gz tar -zxvf openssl-1.0.1j.tar.gz # 4.配置 ./configure # 5.編譯安裝 make && make install
24.4安裝zlib庫
wget //zlib.net/zlib-1.2.11.tar.gz tar -zxvf zlib-1.2.11.tar.gz -C ../module/ cd zlib-1.2.11/ ./configure make && make install
24.5下載Nginx
可以本地上傳或者在線下載
wget //nginx.org/download/nginx-1.16.1.tar.gz cd 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]# ll
total 16
drwxr-xr-x. 2 root root 4096 Dec 25 07:10 conf
drwxr-xr-x. 2 root root 4096 Dec 25 07:10 html
drwxr-xr-x. 2 root root 4096 Dec 25 07:10 logs
drwxr-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.1
ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1