前面我們只講了將靜態頁面上傳到Fastdfs 今天我們將頁面作爲消息發送Message到mq中 然後前臺取到頁面
步驟
首先我們可以在公共的模塊中建一個子模塊hrm-basic-rabbitmq
導入spirngboot集成rabbitmq的依賴
<!--spirngboot集成rabbitmq-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
創建一個存放rabbitmq常量的工具類
//存放rabbitmq的常量,就是消費者和生產者公共東西
public class RabbitMqConstants {
public static final String EXCHANGE_TOPICS_PAGE = "exchange_topics_page";
public static final String FILE_SYS_TYPE = "fileSysType";
public static final String PAGE_URL = "pageUrl";
public static final String PHYSICAL_PATH = "physicalPath";
}
然後在page模塊中引入rabbitmq的模塊引入mq的jar包
<dependency>
<groupId>org.leryoo</groupId>
<artifactId>hrm-basic-rabbitmq</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
Service層
String routingKey = siteMapper.selectById(pager.getSiteId()).getSn();
//消息的內容
Map<String,Object> params = new HashMap<>();
params.put(RabbitMqConstants.FILE_SYS_TYPE,pageConfig.getDfsType()); //文件系統,從哪兒系統系統
params.put(RabbitMqConstants.PAGE_URL,pageConfig.getPageUrl());//從那個路徑下載
params.put(RabbitMqConstants.PHYSICAL_PATH,pageConfig.getPhysicalPath());//下載完了放到哪兒
rabbitTemplate.convertAndSend(
RabbitMqConstants.EXCHANGE_TOPICS_PAGE,routingKey
,JSONObject.toJSONString(params));
創建一個hrm-page-agent-parent模塊
1 這個模塊用來從文件系統下載靜態化頁面的
2 上線時要作爲一個jar和nginx部署在一個服務器上面
3 他沒有common模塊(沒有domain),沒有client(也不給別人調用),只有servie模塊
4 servie模塊開發步驟
1) jar springboot,rabbitmq
2) 配置-rabbitmq(configserver需要)
3 ) 入口類(Eureka)
====
4)zuul訪問映射
5)swagger
4,5不需要,不暴露服務
6)聲明交換機,聲明隊列,把隊列綁定到交換機
7)消費者的handler綁定到隊列
8)實現handler的功能給你
子模塊hrm-page-agent-service-2040
導入相關依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Eureka 客戶端依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--配置中心支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 通過公共rabbitmq的模塊引入mq的jar包-->
<dependency>
<groupId>org.leryoo</groupId>
<artifactId>hrm-basic-rabbitmq</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- fastdfsclient支持-->
<dependency>
<groupId>org.leryoo</groupId>
<artifactId>hrm-common-client</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<!-- 給調用的模塊來轉換json-->
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson 調用者需要轉換-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
然後是配置文件bootstrap.yml
spring:
profiles:
active: dev
cloud:
config:
name: application-page-agent #github上面名稱
profile: ${spring.profiles.active} #環境 java -jar -D xxx jar
label: master #分支
discovery:
enabled: true #從eureka上面找配置服務
service-id: hrm-config-server #指定服務名
#uri: http://127.0.0.1:1299 #配置服務器 單機配置
eureka: #eureka不能放到遠程配置中
client:
service-url:
defaultZone: http://localhost:1010/eureka #告訴服務提供者要把服務註冊到哪兒 #單機環境
instance:
prefer-ip-address: true #顯示客戶端真實ip
feign:
hystrix:
enabled: true #開啓熔斷支持
client:
config:
remote-service: #服務名,填寫default爲所有服務
connectTimeout: 3000
readTimeout: 3000
hystrix:
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
配置倉庫中的配置
server:
port: 2040
spring:
application:
name: hrm-page-agent
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtualHost: /
routingKey: hrmCourseSit
注意因爲生產者和消費者都需要連接rabbitmq 所以在application-page-dev.yml中也需要配置
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtualHost: /
然後是RabbitMqConfig.java
用來聲明交換機和隊列 並將交換機和隊列綁定到在一起
import org.leryoo.util.RabbitMqConstants;
import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfig {
//隊列
public static final String QUEUE_PAGE_STATIC = "queue_page_static";
//交換機名字
public static final String EXCHANGE_TOPICS_PAGE = RabbitMqConstants.EXCHANGE_TOPICS_PAGE;
@Value("${rabbitmq.routingKey}")
private String routingKey;
/**
* 交換機配置
* ExchangeBuilder提供了fanout、direct、topic、header交換機類型的配置
*
* @return the exchange
*/
@Bean(EXCHANGE_TOPICS_PAGE) //spring中bean
public Exchange EXCHANGE_TOPICS_INFORM() {
//durable(true)持久化,消息隊列重啓後交換機仍然存在
return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_PAGE).durable(true).build();
}
//聲明隊列
@Bean(QUEUE_PAGE_STATIC)
public Queue QUEUE_INFORM_SMS() {
Queue queue = new Queue(QUEUE_PAGE_STATIC);
return queue;
}
/**
*
* @param queue the queue
* @param exchange the exchange
* @return the binding
*/
@Bean
public Binding BINDING_QUEUE_INFORM_SMS(@Qualifier(QUEUE_PAGE_STATIC) Queue queue, //通過名字從spring獲取bean
@Qualifier(EXCHANGE_TOPICS_PAGE) Exchange exchange) {
//每個站點的routing可以是不一樣的
System.out.println(routingKey);
return BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();
}
}
StaticPageHandler.java
用來接受消息 並下載到指定的目錄
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import feign.Response;
import org.apache.commons.io.IOUtils;
import org.leryoo.client.FastDfsClient;
import org.leryoo.config.RabbitMqConfig;
import org.leryoo.util.RabbitMqConstants;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
@Component
public class StaticPageHandler {
@RabbitListener(queues = RabbitMqConfig.QUEUE_PAGE_STATIC)
public void handle(String msg, Message message, Channel channel){
System.out.println("接收消息:"+msg);
Map map = JSONObject.parseObject(msg, Map.class);
Integer fileSysType = (Integer) map.get(RabbitMqConstants.FILE_SYS_TYPE);
String pageUrl = (String) map.get(RabbitMqConstants.PAGE_URL);
String physicalPath = (String) map.get(RabbitMqConstants.PHYSICAL_PATH);
//判斷是那個文件系統,分別做處理
switch(fileSysType){
case 0 : //fastdfs
downloadAndCopyOfFastDfs(pageUrl,physicalPath);
break;
case 1 : //hdfs
downloadAndCopyOfHdfs(pageUrl,physicalPath);
break;
}
}
@Autowired
private FastDfsClient fastDfsClient;
//fastdfs支持
private void downloadAndCopyOfFastDfs(String pageUrl, String physicalPath) {
InputStream is = null;
FileOutputStream os = null;
try{
//以pageUrl到fastdfs下載文件
Response response = fastDfsClient.download(pageUrl);
is = response.body().asInputStream();
//放入特定文件
System.out.println(physicalPath);
os = new FileOutputStream(physicalPath);
IOUtils.copy(is,os) ;
}catch (Exception e){
e.printStackTrace();
}
finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//@TODO hdfs以後支持
private void downloadAndCopyOfHdfs(String pageUrl, String physicalPath) {
}
}
最後別忘了寫一個啓動類
然後啓動服務 就ok啦
需要注意的是 因爲我們這裏是生成的靜態頁面 所以我們如果修改了數據後 我們都需要重新生成靜態頁面
課程列表頁
因爲是新的頁面 所以注意跨域問題
1)主頁裏面關鍵字搜索
2)主頁裏面通過類型導航過去.
這裏因爲沒找到課程商城的模板 就隨便找了一個 實現起來都差不多
實現
主頁跳轉列表頁
分析:
①主頁攜帶參數跳轉到列表頁.
location.href = list.html?keyword =xx 關鍵字
轉發到列表頁後進行回顯 回顯到輸入框
然後是一個小功能 麪包屑導航
如果是通過這個地方點進來的 會去搜索文件 也會有一個麪包屑的導航
後臺的實現:
@Override
public List<Map<String, Object>> queryCrumbs(Long courseTypeId) {
List<Map<String,Object>> result = new ArrayList<>();
//1 通過courseTypeId獲取CourseType,從而得到path,就能得到層次結構 .1.2.3. List
String path = courseTypeMapper.selectById(courseTypeId).getPath(); //.1.2.3.
path = path.substring(1,path.length()-1); // 1.2.3
System.out.println(path);
String[] paths = path.split("\\."); //[1,2,3]
//2 對每個節點進行處理 Map
for (String idStr : paths) {
Map<String,Object> node = new HashMap<>();
//2.1 自己
CourseType owerCourseType = courseTypeMapper.selectById(Long.valueOf(idStr));
node.put("ownerCourseType",owerCourseType);
//2.2 兄弟
//2.1.1 獲取父親的所有兒子
Long pid = owerCourseType.getPid();
List<CourseType> allChirdren = courseTypeMapper
.selectList(new EntityWrapper<CourseType>().eq("pid", pid));
//2.1.2 刪除自己
Iterator<CourseType> iterator = allChirdren.iterator();
while (iterator.hasNext()){
CourseType type = iterator.next();
//自己id爲遍歷出來的id
if (owerCourseType.getId().intValue()==type.getId().intValue()){
iterator.remove();
break;
}
}
node.put("otherCourseTypes",allChirdren);
result.add(node);
}
return result;
}
然後是搜索功能
後臺實現
@Override
public PageList<EsCourse> queryCourses(CourseQuery query) {
NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
//1條件
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
builder.withQuery(boolQuery);
//2 排序
FieldSortBuilder order = SortBuilders.fieldSort(query.getSortField()).order(SortOrder.DESC);
builder.withSort(order);
//3 分頁
builder.withPageable(PageRequest.of(query.getPage()-1,query.getRows()));
//4 截取字段 先不多
//5 查詢封裝
NativeSearchQuery esQuery = builder.build();
org.springframework.data.domain.Page<EsCourse> page =
repository.search(esQuery);
return new PageList<>(page.getTotalElements(),page.getContent());
}