好好學習,天天向上
本文已收錄至我的Github倉庫DayDayUP:github.com/RobodLee/DayDayUP,歡迎Star,更多文章請前往:目錄導航
- 暢購商城(一):環境搭建
- 暢購商城(二):分布式文件系統FastDFS
- 暢購商城(三):商品管理
- 暢購商城(四):Lua、OpenResty、Canal實現廣告緩存與同步
- 暢購商城(五):Elasticsearch實現商品搜索
- 暢購商城(六):商品搜索
- 暢購商城(七):Thymeleaf實現靜態頁
- 暢購商城(八):微服務網關和JWT令牌
- 暢購商城(九):Spring Security Oauth2
- 暢購商城(十):購物車
- 暢購商城(十一):訂單
- 暢購商城(十二):接入微信支付
- 暢購商城(十三):秒殺系統「上」
- 暢購商城(十四):秒殺系統「下」
啰嗦幾句
暢購商城是黑馬的一個項目。要說這個項目有多難,跟着視頻做肯定是沒什么大問題了,但是可以讓我知道一個項目的具體開發流程以及提高自己對於一系列框架使用的熟練度,這也是我做這個項目的目的。關於這個項目的資料我就不提供了,視頻b站上面有,配套的資料也在視頻下面的評論中,有需要的朋友直接到b站上面找就可以了。接下來我會用十幾篇文章來記錄一下整個項目的開發經過以及遇到的問題。
暢購商城項目介紹
暢購商城項目是一個B2C的電商網站,采用了微服務架構,並且使用了前后端分離的方式進行開發。
技術棧
上面這張圖就是暢購商城使用到的技術棧,從圖中可以看出,整個微服務的開發是基於SpringBoot的,OAuth2.0是用來進行授權操作的,JWT用來封裝用戶的授權信息,Spring AMQP是消息隊列協議。然后就是一套Spring Cloud的微服務框架。
持久化技術棧選用了MyBatis+通用Mapper,但我不准備用通用Mapper,因為我想鍛煉一下寫SQL語句,平時SQL也沒怎么寫,就借此機會練習練習。還用到了SpringDataEs用來操作ElasticSearch,SpringDataRedis用來操作Redis。
數據庫采用了MySQL,消息隊列選用了RabbitMQ,還實現了MySQL讀寫分離。
支付接口就選擇了微信支付。
技術架構
這張圖是暢購商城的技術架構圖,可以看到,先是使用了Nginx做負載均衡以及限流;緊跟着的就是微服務網關,是用來將請求路由到不同的微服務,網關也集成了限流和權限校驗的功能。后面就是具體的微服務了,業務方面一共分為了7個微服務,微服務之間也可能會相互調用,采用了Feign來進行不同微服務之間的調用,一些JavaBean及工具類也被單獨抽取了出來。一些公共組件微服務也被單獨抽取了出來,比如Oauth2.0微服務,RabbitMQ微服務等。
Hystrix Dashboard作為監控中心,Eureka是微服務的注冊中心。
數據支撐方面,搜索功能用的是ElasticSearch,文件系統采用的是FastDFS,數據庫選用的當然是MySQL了,緩存用的是Redis。
這里面有很多我也沒用過,具體是干什么的我也不是很清楚,介紹的就簡單了點。
環境搭建
項目介紹得差不多了就開始搭建項目吧。
安裝虛擬機,准備數據庫
我們用到的MySQL數據庫是安裝在docker中的,docker安裝在了CentOS上,這些都已經安裝好了,我們只需要把黑馬提供的虛擬機安裝一下就可以了。安裝過程很簡單,但是安裝完成后一定要記得改IP,因為虛擬機的靜態IP和我們自己的電腦可能不在一個網段,改到一個網段。還有一個問題就是用Navicat連不上數據庫,可能的原因是數據庫密碼不對
,視頻上說的是123456,可我試了是root;要么就是沒有允許遠程訪問
,開啟就好;最后一個原因就是防火牆不允許我們訪問3306端口
,把防火牆關閉就OK了。
項目框架搭建
1. 創建父工程
在changgou目錄下創建一個新的Module名為changou-parent作為整個項目的父工程:
在父工程里面不需要寫代碼,所以把src目錄刪掉。因為每個微服務工程都是SpringBoot的,所以在changgou-parent的pom文件中添加SpringBoot的起步依賴。然后再添加一些需要用到的依賴包,視頻里還添加了swagger的依賴,但是暫時不准備用,等用的時候再添加。整個changgou-parent的pom文件的內容我貼在了下面:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.robod</groupId>
<artifactId>changgou-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<description>
暢購商城項目的父工程
</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<properties>
<!-- 跳過測試 -->
<skipTests>true</skipTests>
</properties>
<!--依賴包-->
<dependencies>
<!--測試包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2. 其它幾個公共模塊搭建
在changgou-parent下面創建changgou-gateway、changgou-service、changgou-service-api、changgou-web四個Module,因為這幾個是各個模塊的父工程,所以也不用寫代碼,刪除src目錄,並且打pom包。
<packaging>pom</packaging>
3. Eureka微服務搭建
微服務工程都搭建完畢了,現在就需要有個注冊中心去啟動微服務,所以接下來就在changgou-parent下創建一個名為changgou-eureka的Module,要想開啟eureka的服務,就需要添加相應的依賴包。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
接下來在resource目錄下添加配置文件application.yml:
server:
port: 7001 #端口號
eureka:
instance:
hostname: 127.0.0.1 #ip
client:
register-with-eureka: false #是否將自己注冊到eureka中
fetch-registry: false #是否從eureka中獲取信息
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
spring:
application:
name: eureka
最后在java包下添加一個啟動類:com.robod.EurekaApplication:
@SpringBootApplication
@EnableEurekaServer //開啟Eureka服務
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class,args);
}
}
現在就來測試一下Eureka能不能啟動成功,運行上面的代碼,等項目啟動起來,訪問http://127.0.0.1:7001
成功出現了上面的界面,說明我們的注冊中心已經搭建成功了👍
4. 創建common工程
不同的微服務里面都會使用到一些相同的工具類,我們將這些工具類抽取到一個單獨的子工程里面,在changgou-parent下面新建一個Module叫做changgou-common,在pom文件中添加所需的依賴。
<dependencies>
<!--web起步依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- redis 使用-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--eureka-client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--微信支付-->
<dependency>
<groupId>com.github.wxpay</groupId>
<artifactId>wxpay-sdk</artifactId>
<version>0.0.3</version>
</dependency>
<!--httpclient支持-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
</dependencies>
最后在com.robod.entity包下添加幾個工具類(這些類在配套資料里面都有):
5. 數據庫工程搭建
這個工程是將需要訪問數據庫的一些依賴進行一個匯總,沒有代碼,在chnaggou-parent下新建一個Module叫changgou-common-db,然后刪除src目錄,最后添加所需的依賴:
<!--依賴-->
<dependencies>
<!--對changgou-common的依賴-->
<dependency>
<groupId>com.robod</groupId>
<artifactId>changgou-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--通用mapper起步依賴,我不需要,所以沒有添加這個-->
<!-- <dependency>-->
<!-- <groupId>tk.mybatis</groupId>-->
<!-- <artifactId>mapper-spring-boot-starter</artifactId>-->
<!-- <version>2.0.4</version>-->
<!-- </dependency>-->
<!--MySQL數據庫驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--mybatis分頁插件-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
商品微服務工程
1. 商品微服務的JavaBean工程
前面我們創建了一個changgou-service-api用來管理所有的微服務工程的API抽取,現在我們就在changgou-service-api下創建一個changogu-service-goods-api工程用來管理商品微服務的JavaBean,為了簡化代碼,我們需要用到Lombok,將Lombok的依賴添加到changgou-service-api的pom文件中:
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
</dependencies>
然后將我們需要的一些JavaBean放到com.robod.goods.pojo包下。
2. 創建商品微服務工程changgou-service-goods
在changgou-service下面創建一個changgou-service-goods作為商品微服務工程,因為要使用連接數據庫的一些東西,所以我們將changgou-common-db引入到changgou-service中:
<dependency>
<groupId>com.robod</groupId>
<artifactId>changgou-common-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
微服務工程自然少不了配置文件,在resources目錄下創建application.yml
server:
port: 18081
spring:
application:
name: goods
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://192.168.31.200:3306/changgou_goods?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
username: root
password: root
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
最后為這個工程創建一個啟動類com.robod.GoodsApplication:
@SpringBootApplication
@EnableEurekaClient //開啟Eureka客戶端
@MapperScan("com.robod.mapper") //開啟包掃描
@EnableTransactionManagement //事務管理
public class GoodsApplication {
public static void main(String[] args) {
SpringApplication.run(GoodsApplication.class, args);
}
}
將項目啟動起來,訪問http://127.0.0.1:7001。
可以看到,商品微服務工程已經成功啟動並且注冊到Eureka中了。
3. 查詢所有品牌功能實現
分別創建出Controller層,Service層,Dao層對應的類:
寫出對應的代碼:
@Repository("brandMapper")
public interface BrandMapper {
/**
* 查詢所有的品牌信息
* @return
*/
@Select("select * from tb_brand")
public List<Brand> findAll();
}
-------------------------------------------------------
@Service("brandService")
@Transactional(rollbackFor = Exception.class) //異常回滾
public class BrandServiceImpl implements BrandService {
private final BrandMapper brandMapper;
public BrandServiceImpl(BrandMapper brandMapper) {
this.brandMapper = brandMapper;
}
@Override
public List<Brand> findAll() {
return brandMapper.findAll();
}
}
---------------------------------------------------------
@RestController
@RequestMapping("/brand")
@CrossOrigin
public class BrandController {
private final BrandService brandService;
public BrandController(BrandService brandService) {
this.brandService = brandService;
}
@GetMapping
public Result<List<Brand>> findAll() {
List<Brand> brands = brandService.findAll();
return new Result<>(true, StatusCode.OK,"查詢成功",brands);
}
}
然后將項目運行起來,訪問http://localhost:18081/brand
成功查詢出所有的品牌信息,說明我們的環境搭建成功了,剩下的修改品牌,刪除品牌等功能直接寫就可以了,如果不行很有可能是代碼有問題,不是環境問題。
4. 分頁 + 條件查詢
分頁查詢我們需要用到PageHelper,這個依賴我們前面已經添加過了。直接上代碼:
public PageInfo<Brand> findPage(Brand brand, int page, int size) {
PageHelper.startPage(page,size);
List<Brand> brands = brandMapper.findList(brand);
return new PageInfo<>(brands);
}
很簡單,先是PageHelper.startPage(page,size),page是需要獲取第幾頁的數據,size是每頁的數據條數;再調用方法拿到所有數據;最后使用一個PageInfo將數據封裝起來即可。
條件查詢就需要根據條件動態構建SQL語句:
@SelectProvider(type = BrandMapperProvider.class, method = "findList")
public List<Brand> findList(Brand brand);
class BrandMapperProvider {
public String findList(Brand brand) {
StringBuilder builder = new StringBuilder("select * from tb_brand where ");
if (!StringUtils.isEmpty(brand.getName())) {
builder.append(" name like ").append("\"%").append(brand.getName()).append("%\" ");
}
if (!StringUtils.isEmpty(brand.getImage())) {
builder.append(" and image like ").append("\"%").append(brand.getImage()).append("%\" ");
}
if (!StringUtils.isEmpty(brand.getLetter())) {
builder.append(" and letter = ").append(" \"").append(brand.getLetter()).append("\" ");
}
if (brand.getSeq() != null) {
builder.append(" and seq = ").append(brand.getSeq());
}
System.out.println(builder.toString());
return builder.toString();
}
}
在BrandMapper中添加一個內部類BrandMapperProvider,並提供一個構建SQL語句的方法,最后在findList方法上面添加注解@SelectProvider即可。
測試一下:
成功得到了我們想要的結果。
全局異常處理
為每個方法都寫異常處理代碼實在是太麻煩了,可以用一個全局異常處理類去處理所有的異常。因為所有的微服務工程都依賴了changgou-common,所以我們可以直接在changgou-common工程下的com.robod.exception包下創建一個類BaseExceptionHandler。
@ControllerAdvice
public class BaseExceptionHandler {
/***
* 異常處理
* @param e
* @return
*/
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result error(Exception e) {
e.printStackTrace();
return new Result(false, StatusCode.ERROR, e.getMessage());
}
}
在類的上面添加@ControllerAdvice注解,在這里的作用是應用到所有@RequestMapping中,實現全局異常處理,該注解還可以實現全局數據綁定以及全局數據預處理的功能。在error方法上面添加@ExceptionHandler(value=Exception.class)注解,用於聲明所需要捕獲的異常的類型。最后在error方法中編寫異常處理的代碼。
小結
這篇文章主要介紹了暢購商城的架構以及環境的搭建,然后寫了個商品微服務工程,並實現了對品牌表的增刪查改功能。最后我們還實現了全局異常處理功能,下一篇文章就寫一寫分布式文件系統fastDFS環境的搭建過程以及遇到的一些問題。
如果我的文章對你有些幫助,不要忘了點贊,收藏,轉發,關注。要是有什么好的意見歡迎在下方留言。讓我們下期再見!