页面静态化

1.当页面数据发生变化时触发页面静态化方法

页面数据发生改变时触发页面静态化方法
1.将改变的数据存放到redis中
2.将数据在redis中的key和需要静态化的页面名称通过feign发送给页面静态化服务
3.页面静态化服务通过页面名字从数据库中查找页面的模板,并下载解压到本地临时目录
4.通过key从redis中查找静态化需要的数据
5.将数据和模板整合生成html
6.将html上传到fastdfs
7.在静态化服务端集成rabbitmq发送端
8.在nginx端设置代理服务,集成rabbitmq接收端,从fastdfs下载html,并将html放到nginx目录中

private void doStaticForHome(){
        //页面静态化的数据存储到redis
        List<CourseType> courseTypesDataTree = selectList(null);
        //将课程类型转成json
        String data = JSON.toJSONString(courseTypesDataTree);
        //将数据保存到redis
        redisClient.set(RedisContants.KEY_DATATREE_COURSE_TYPE, data);
        HashMap<String, String> map = new HashMap<>();
        //页面静态化页面名称
        map.put(PageStaticContants.STATIC_PAGE_NAME, PageStaticContants.STATIC_COURSETYPE);
        //页面静态化存在redis中的key
        map.put(PageStaticContants.STATIC_PAGE_DATA, RedisContants.KEY_DATATREE_COURSE_TYPE);
        //页面静态化数据需要封装到那个key中
        map.put(PageStaticContants.TEMPLATE_DATA_KEY, "courseTypes");
        //调用页面静态化服务
        pageClient.pageStatic(map);
    }

2.页面静态化服务

2.1jar包

		<!--velocity依赖包-->
        <dependency>
            <groupId>org.apache.velocity</groupId>
            <artifactId>velocity</artifactId>
        </dependency>
        <!--spirngboot集成rabbitmq-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
		...

2.2 application.yml

spring:
  application:
    name: page-server
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql:///hrm_page
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
mybatis-plus:
  mapper-locations: classpath:com/wal/hrm/mapper\/*Mapper.xml

server:
  port: 2070
  max-http-header-size: 102400000
  tomcat:
    max-http-header-size: 102400000

eureka:
  instance:
    hostname: page-server
    instance-id: page-server:2070
    prefer-ip-address: true
  client:
    service-url:
      defaultZone: http://peer1:1010/eureka/

rabbitmq:
  host: 127.0.0.1
  port: 5672
  username: guest
  password: guest
  virtualHost: /

feign:
  hystrix:
    enabled: true #开启熔断支持
  client:
    config:
      remote-service:           #服务名,填写default为所有服务
        connectTimeout: 3000
        readTimeout: 3000
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 50000  

2.3.主配置类

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableTransactionManagement
@Import({Swagger2.class, MyBatisPlusConfig.class})
public class PageServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(PageServerApplication.class);
    }
}

2.4页面静态化controller

@RestController
@RequestMapping("/static")
@CrossOrigin
public class PageStaticController {
    @Autowired
    private IPageStaticServer pageStaticServer;
    @PostMapping("/page")
    public AjaxResult pageStatic(@RequestBody Map map){
        AjaxResult result = pageStaticServer.pageStatic(map);
        return result;
    }
}

2.5页面静态化service

 public AjaxResult pageStatic(Map map) {
        //根据页面名字从数据库中查找模板的存放路径
        String name =(String) map.get(PageStaticContants.STATIC_PAGE_NAME);
        Page page = pageMapper.findPageByName(name);
        String templateUrl = page.getTemplateUrl();
        //处理路径判断是不是 / 开头
        String path = templateUrl.startsWith("/")?templateUrl.substring(1):templateUrl;
        //拿到组名先找到第一个/的位置
        int index = path.indexOf("/");
        String groupName=path.substring(0, index);
        String fileName=path.substring(index+1);
        //从fastdfs下载模板
        byte[] result = fastDfsClient.download(groupName, fileName);
        if (result == null || result.length<1){
            throw new MyException(ErrorCode.ERROR_CODE_TEMPLATE_DOWNLOAD_ERROR.getErrorMsg());
        }
        //将模板保存到本地:系统临时目录C:\Users\*****\AppData\Local\Temp\
        String basicPath = System.getProperty("java.io.tmpdir")+"template\\";
        String templateName =name+".zip";
        String filepath = basicPath + templateName;
        try {
            File file = new File(filepath);
            if (!file.exists()){
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            FileCopyUtils.copy(result, file);
            //解压模板
            ZipUtils.unZip(filepath, basicPath);
            //生成html
            //拿到数据需要包装的key
            String dataKey = (String) map.get(PageStaticContants.TEMPLATE_DATA_KEY);
            //拿到数据在redis中的key
            String keyData = (String) map.get(PageStaticContants.STATIC_PAGE_DATA);
            //从redis中查出数据
            AjaxResult result1 = redisClient.get(keyData);
            JSONArray dataRes = JSON.parseArray(result1.getResultObj().toString());
            HashMap<String, Object> model = new HashMap<>();
            model.put(dataKey, dataRes);
            model.put("staticRoot", basicPath);
            //模板的路径
            String templatePath = basicPath+name+".vm";
            //html输出路径
            String htmlPath = basicPath+name+".html";
            VelocityUtils.staticByTemplate(model, templatePath, htmlPath);
            //将html上传到fastdfs
            byte[] bytes = FileCopyUtils.copyToByteArray(new File(htmlPath));

            AjaxResult result2 = fastDfsClient.uploadhtml(bytes, "html");
            if(!result2.isSuccess()){
                throw new MyException(ErrorCode.ERROR_CODE_HTML_UPLOAD_ERROR.getErrorMsg());
            }
            //保存配置信息
            PageConfig pageConfig = new PageConfig();
            pageConfig.setDataKey(keyData);
            pageConfig.setDfsType(1l);
            pageConfig.setPageId(page.getId());
            pageConfig.setPageUrl(result2.getResultObj().toString());
            pageConfig.setPhysicalPath(page.getPhysicalPath());
            pageConfig.setTemplateUrl(page.getTemplateUrl());
            pageConfigMapper.insert(pageConfig);
            //查询routingKey
            String routingKey = siteMapper.selectById(page.getSiteId()).getSn();
            //准备发送的消息
            HashMap<String, Object> map1 = new HashMap<>();
            //html的存放地址
            map1.put(MqContants.HTML_PATH, result2.getResultObj().toString());
            //存放到nginx的地址
            map1.put(MqContants.NGINX_PATH, page.getPhysicalPath().toString());
            String msg = JSON.toJSONString(map1);
            //向nginx代理发送mq消息
            rabbitTemplate.convertAndSend(MqContants.EXCHANGE_NAME,routingKey ,msg);

        } catch (Exception e) {
            e.printStackTrace();
        }


        return AjaxResult.me();
    }

2.6.velocityutils

public class VelocityUtils {
	private static Properties p = new Properties();
	static {
		p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
		p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
		p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
		p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
	}
	
	/**
	 * 返回通过模板,将model中的数据替换后的内容
	 * @param model
	 * @param templateFilePathAndName
	 * @return
	 */
	public static String getContentByTemplate(Object model, String templateFilePathAndName){
		try {
			Velocity.init(p);
			Template template = Velocity.getTemplate(templateFilePathAndName);
			VelocityContext context = new VelocityContext();
			context.put("model", model);
			StringWriter writer = new StringWriter();
			template.merge(context, writer);
			String retContent = writer.toString();
			writer.close();
			return retContent;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 根据模板,静态化model到指定的文件 模板文件中通过访问model来访问设置的内容
	 * 
	 * @param model
	 *            数据对象
	 * @param templateFilePathAndName
	 *            模板文件的物理路径
	 * @param targetFilePathAndName
	 *            目标输出文件的物理路径
	 */
	public static void staticByTemplate(Object model, String templateFilePathAndName, String targetFilePathAndName) {
		try {
			Velocity.init(p);
			Template template = Velocity.getTemplate(templateFilePathAndName);
			
			VelocityContext context = new VelocityContext();
			context.put("model", model);
			FileOutputStream fos = new FileOutputStream(targetFilePathAndName);
			BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));// 设置写入的文件编码,解决中文问题
			template.merge(context, writer);
			writer.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 静态化内容content到指定的文件
	 * 
	 * @param content
	 * @param targetFilePathAndName
	 */
	public static void staticBySimple(Object content, String targetFilePathAndName) {
		VelocityEngine ve = new VelocityEngine();
		ve.init(p);
		String template = "${content}";
		VelocityContext context = new VelocityContext();
		context.put("content", content);
		StringWriter writer = new StringWriter();
		ve.evaluate(context, writer, "", template);
		try {
			FileWriter fileWriter = new FileWriter(new File(targetFilePathAndName));
			fileWriter.write(writer.toString());
			fileWriter.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

2.7.ziputils

package com.wal.hrm.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipFile;
import org.apache.tools.zip.ZipOutputStream;

/**
 * <p>
 * ZIP工具包
 * </p>
 * <p>
 * 依赖:ant-1.7.1.jar
 * </p>
 * 
 * @author IceWee
 * @date 2012-5-26
 * @version 1.0
 */
public class ZipUtils {
    
    /**
     * 使用GBK编码可以避免压缩中文文件名乱码
     */
    private static final String CHINESE_CHARSET = "GBK";
    
    /**
     * 文件读取缓冲区大小
     */
    private static final int CACHE_SIZE = 1024;
    
    /**
     * <p>
     * 压缩文件
     * </p>
     * 
     * @param sourceFolder 压缩文件夹
     * @param zipFilePath 压缩文件输出路径
     * @throws Exception
     */
    public static void zip(String sourceFolder, String zipFilePath) throws Exception {
        OutputStream out = new FileOutputStream(zipFilePath);
        BufferedOutputStream bos = new BufferedOutputStream(out);
        ZipOutputStream zos = new ZipOutputStream(bos);
        // 解决中文文件名乱码
        zos.setEncoding(CHINESE_CHARSET);
        File file = new File(sourceFolder);
        String basePath = null;
        if (file.isDirectory()) {
            basePath = file.getPath();
        } else {
            basePath = file.getParent();
        }
        zipFile(file, basePath, zos);
        zos.closeEntry();
        zos.close();
        bos.close();
        out.close();
    }
    
    /**
     * <p>
     * 递归压缩文件
     * </p>
     * 
     * @param parentFile
     * @param basePath
     * @param zos
     * @throws Exception
     */
    private static void zipFile(File parentFile, String basePath, ZipOutputStream zos) throws Exception {
        File[] files = new File[0];
        if (parentFile.isDirectory()) {
            files = parentFile.listFiles();
        } else {
            files = new File[1];
            files[0] = parentFile;
        }
        String pathName;
        InputStream is;
        BufferedInputStream bis;
        byte[] cache = new byte[CACHE_SIZE];
        for (File file : files) {
            if (file.isDirectory()) {
                zipFile(file, basePath, zos);
            } else {
                pathName = file.getPath().substring(basePath.length() + 1);
                is = new FileInputStream(file);
                bis = new BufferedInputStream(is);
                zos.putNextEntry(new ZipEntry(pathName));
                int nRead = 0;
                while ((nRead = bis.read(cache, 0, CACHE_SIZE)) != -1) {
                    zos.write(cache, 0, nRead);
                }
                bis.close();
                is.close();
            }
        }
    }
    
    /**
     * <p>
     * 解压压缩包
     * </p>
     * 
     * @param zipFilePath 压缩文件路径
     * @param destDir 压缩包释放目录
     * @throws Exception
     */
    public static void unZip(String zipFilePath, String destDir) throws Exception {
        ZipFile zipFile = new ZipFile(zipFilePath, CHINESE_CHARSET);
        Enumeration<?> emu = zipFile.getEntries();
        BufferedInputStream bis;
        FileOutputStream fos;
        BufferedOutputStream bos;
        File file, parentFile;
        ZipEntry entry;
        byte[] cache = new byte[CACHE_SIZE];
        while (emu.hasMoreElements()) {
            entry = (ZipEntry) emu.nextElement();
            if (entry.isDirectory()) {
                new File(destDir + entry.getName()).mkdirs();
                continue;
            }
            bis = new BufferedInputStream(zipFile.getInputStream(entry));
            file = new File(destDir + entry.getName());
            parentFile = file.getParentFile();
            if (parentFile != null && (!parentFile.exists())) {
                parentFile.mkdirs();
            }
            fos = new FileOutputStream(file);
            bos = new BufferedOutputStream(fos, CACHE_SIZE);
            int nRead = 0;
            while ((nRead = bis.read(cache, 0, CACHE_SIZE)) != -1) {
                fos.write(cache, 0, nRead);
            }
            bos.flush();
            bos.close();
            fos.close();
            bis.close();
        }
        zipFile.close();
    }
    
}

2.7rabbitMq配置

@Configuration
public class MqConfig {
    //配置交换机
    @Bean(MqContants.EXCHANGE_NAME)
    public Exchange exchange_name(){
        return ExchangeBuilder.directExchange(MqContants.EXCHANGE_NAME).durable(true).build();
    }
}

3.nginx代理服务,替nginx下载html

3.1application.yml

spring:
  application:
    name: proxy-server
server:
  port: 2080

eureka:
  instance:
    hostname: proxy-server
    prefer-ip-address: true
    instance-id: proxy-server:2080
  client:
    service-url:
      defaultZone: http://peer1:1010/eureka/

rabbitmq:
  host: 127.0.0.1
  port: 5672
  username: guest
  password: guest
  virtualHost: /

mq:
  routingKey: hrmHomeSite

feign:
  hystrix:
    enabled: true #开启熔断支持
  client:
    config:
      remote-service:           #服务名,填写default为所有服务
        connectTimeout: 30000
        readTimeout: 30000
hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 30000

3.2接收端rabbitMq配置

接收端routingKey和发送短routingKey需要一致

@Configuration
public class MqConfig {
    @Value("${mq.routingKey}")
    private String routingKey;
    //设置消息队列
    @Bean
    public Queue staticQueue(){
        return new Queue(routingKey,true);
    }
    //设置交换机
    @Bean(MqContants.EXCHANGE_NAME)
    public Exchange exchange(){
        return ExchangeBuilder.directExchange(MqContants.EXCHANGE_NAME)
                .durable(true).build();
    }
    //将队列绑定到交换机
    @Bean
    public Binding binding(@Qualifier(MqContants.EXCHANGE_NAME) Exchange exchange,
                           @Qualifier("staticQueue") Queue queue){
        return BindingBuilder.bind(queue).to(exchange).with(routingKey).noargs();

    }

}

3.3 消息接收html上传

@Component
public class ReserveMsg {
    @Autowired
    FastDfsClient fastDfsClient;
    //@Value("${mq.routingKey}")
    private static final String routingKey = "hrmHomeSite";
    @RabbitListener(queues =routingKey)
    public void recive(String msg, Message message, Channel channel){
        Map map = JSON.parseObject(msg, Map.class);
        //拿到html地址
        String htmlPath = map.get(MqContants.HTML_PATH).toString();
        String path = htmlPath.startsWith("/")?htmlPath.substring(1):htmlPath;
        int index = path.indexOf("/");
        String groupName=path.substring(0, index);
        String fileName = path.substring(index+1);
        //从fastdfs下载html
        byte[] html = fastDfsClient.download(groupName, fileName);
        if (html==null || html.length<1){
            throw new MyException(ErrorCode.ERROR_CODE_HTML_DOWNLOAD_ERROR.getErrorMsg());
        }
        //将html拷贝到指定目录
        String nginxPath = map.get(MqContants.NGINX_PATH).toString();
        File file = new File(nginxPath);
        try {
            if (!file.exists()){
                file.getParentFile().mkdirs();
                file.createNewFile();
            }
            FileCopyUtils.copy(html, file);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4当通过feign调用服务超时

可以在application.yml上添加

##服务调用超时时间设置
ribbon:
  ReadTimeout: 60000
  ConnectTimeout: 60000
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值