静态化
静态化是在项目中比较常见的一种技术,实现起来也非常简单。无非就是先将访问的资源保存为html文件,访问时优先访问html。不过在静态化之前还需要做一些准备工作。
1.将访问路径编写成rest风格的,如下:
@RequestMapping("/index/{moduleId}/{reportId}")
2.将ajax请求尽可能的转化成同步加载的,这样静态化的时候才会尽可能多的静态化数据,当然是用ajax也可以,只不过是用ajax的数据就不会被静态化了。
3.提前将所有界面都生成html文件,这里是用了spring的定时任务根据自己的实际情况更新数据。我们的数据仓库每天晚上更新一次,所以我们这里的静态化的线上定时时间也是每天晚上在数据仓库更新了之后运行,静态化了之后减轻了数据库和服务器的压力,访问速度当然也快了好几倍
1 <dependency> 2 <groupId>commons-httpclient</groupId> 3 <artifactId>commons-httpclient</artifactId> 4 <version>3.1</version> 5 </dependency>
1 package com.demo.task; 2 3 import java.io.File; 4 import java.io.FileOutputStream; 5 import java.io.IOException; 6 import java.util.HashMap; 7 import java.util.List; 8 import java.util.Map; 9 10 import org.apache.commons.httpclient.HttpClient; 11 import org.apache.commons.httpclient.methods.GetMethod; 12 import org.apache.log4j.Logger; 13 import org.springframework.beans.factory.annotation.Autowired; 14 import org.springframework.context.support.GenericXmlApplicationContext; 15 import org.springframework.scheduling.annotation.Scheduled; 16 import org.springframework.stereotype.Component; 17 import org.springframework.test.context.ContextConfiguration; 18 19 import com.demo.controller.paramvo.DataReportParam; 20 import com.demo.entity.DataModule; 21 import com.demo.entity.DataReport; 22 import com.demo.service.IDataModuleService; 23 import com.demo.service.IDataReportService; 24 25 /** 26 * 静态化 27 */ 28 @Component 29 @ContextConfiguration(locations = "/applicationContext.xml") 30 public class StaticHtml { 31 32 33 private Logger logger = Logger.getLogger(StaticHtml.class); 34 /** 静态化URL */ 35 public String static_url = "/dpf/main/index/${moduleId}/${reportId}"; 36 /** 静态化界面名称 */ 37 public static String static_name = "main_index_${moduleId}_${reportId}.html"; 38 /** 判断是否是windows系统 */ 39 public final static boolean IS_LOCAL = System.getProperty("os.name").startsWith("win")||System.getProperty("os.name").startsWith("Win"); 40 /** 网址(可以考虑IP,指定WEB来处理) */ 41 private final String LOGON_SITE = IS_LOCAL?"172.16.5.16":"192.168.99.96";; 42 /** 端口 */ 43 private final int LOGON_PORT = IS_LOCAL?8080:8080;; 44 private HttpClient client = new HttpClient(); 45 /** 运行锁 */ 46 public boolean EXEC_LOCK = false; 47 public static String static_root = "/templates/temp/"; 48 /** 静态页面存放根目录 */ 49 private final static String INDEX_HOME_ROOT = IS_LOCAL?"/home/admin/view"+static_root 50 :"/home/admin/view"+static_root; 51 52 /** 同步文件shell脚本 */ 53 private String scp_command = "scp -r /home/admin/view/templates/temp/ 192.168.99.97:/home/admin/view/templates/"; 54 /** 静态化列表 URL - 是否静态化 1-是 0-否 */ 55 public HashMap<String,Integer> static_html = new HashMap<String,Integer>(); 56 private GenericXmlApplicationContext context = new GenericXmlApplicationContext(); 57 /** 模块 */ 58 @Autowired private IDataModuleService dataModuleService; 59 /** 报表 */ 60 @Autowired private IDataReportService dataReportService; 61 /** 62 * @功能描述: 初始化client 63 * @创建作者: ** 64 * @创建日期: 2016年10月17日 下午2:16:14 65 */ 66 public void createClient(){ 67 client.getHostConfiguration().setHost(LOGON_SITE, LOGON_PORT); 68 } 69 70 /** 71 * @功能描述: 添加URL 72 * @param moduleId 模块id 73 * @param reportId 报表id 74 */ 75 private void addUrl(String moduleId, String reportId){ 76 static_html.put(static_url.replace("${moduleId}", moduleId) 77 .replace("${reportId}", reportId),0); 78 } 79 80 /** 81 * @功能描述: 初始化URL 82 */ 83 private void initUrl(){ 84 List<DataModule> modules = dataModuleService.queryAll(); 85 for(int i=0; i< modules.size(); i++) { 86 Long moduleId = modules.get(i).getId(); 87 DataReportParam vo = new DataReportParam(); 88 vo.setModuleId(moduleId); 89 List<DataReport> reports = dataReportService.queryList(vo); 90 for(int j=0; j< reports.size(); j++) { 91 Long reportId = reports.get(j).getId(); 92 addUrl(moduleId.toString(), reportId.toString()); 93 } 94 } 95 } 96 97 /** 98 * @throws IOException 99 * @功能描述: 首页静态化任务 30MIN执行一次(根据访问量来设置更新时间) 100 * @创建作者: ** 101 * @创建日期: 2016年10月17日 下午2:15:53 102 */ 103 @Scheduled(cron="* 0/30 * * * ?") 104 public synchronized void exec() throws IOException { 105 EXEC_LOCK=true; 106 long s = System.currentTimeMillis(); 107 logger.info("-----------首页缓存开始-----------"); 108 createClient(); 109 //初始化需要静态化界面的url 110 static_html = new HashMap<String,Integer>(); 111 initUrl(); 112 File folder = new File(INDEX_HOME_ROOT); 113 if(!folder.exists()) 114 folder.mkdirs(); 115 int i=0; 116 int a=static_html.size(); 117 logger.info("共计缓存界面"+a+"个"); 118 System.out.println("共计缓存界面"+a+"个"); 119 for (Map.Entry<String, Integer> entry : static_html.entrySet()) { 120 i++; 121 String url = entry.getKey(); 122 Integer is_static = entry.getValue(); 123 Integer p = (int) (Double.valueOf(i)/a*100); 124 logger.info(url+" 成功("+p+"%)"); 125 System.out.println(url+" 成功("+p+"%)"); 126 if(is_static!=1){ 127 GetMethod get = new GetMethod(url); 128 //模拟表单元素 129 File file = null; 130 FileOutputStream is = null; 131 try { 132 String moduleId = url.split("/")[4]; 133 String reportId = url.split("/")[5]; 134 String fileName = static_name.replace("${moduleId}", moduleId).replace("${reportId}", reportId); 135 file = new File(INDEX_HOME_ROOT+fileName); 136 is = new FileOutputStream(file); 137 int status = client.executeMethod(get); 138 if(status>=200&&status<400){ 139 String html = get.getResponseBodyAsString(); 140 is.write(html.getBytes()); 141 logger.info(url+" 成功("+p+"%)"); 142 }else{ 143 logger.info(url+" 失败("+p+"%)"); 144 } 145 } catch (Exception e) { 146 logger.error("首页缓存失败",e); 147 } finally{ 148 if(is != null){ 149 is.flush(); 150 is.close(); 151 } 152 } 153 entry.setValue(1); 154 } 155 } 156 157 logger.info("-----------缓存结束-----------"); 158 long e = System.currentTimeMillis(); 159 logger.info("-----------耗时:"+(e-s)/1000+"秒-----------"); 160 EXEC_LOCK=false; 161 } 162 163 /** 164 * @功能描述: 判断缓存界面是否存在 165 * @创建作者: ** 166 * @创建日期: 2016年10月17日 下午3:05:26 167 * @param cityCode 168 * @return 169 */ 170 public static boolean existsStatic(Long moduleId, Long reportId){ 171 String fileName = static_name.replace("${moduleId}", moduleId.toString()).replace("${reportId}", reportId.toString()); 172 File file = new File(INDEX_HOME_ROOT+fileName); 173 if(file.exists() && file.length()>0){ 174 return true; 175 } 176 return false; 177 } 178 179 /** 180 * @功能描述: 调用静态化界面 181 * @创建作者: ** 182 * @创建日期: 2016年9月29日 下午4:47:06 183 * @param args 184 */ 185 public void main(String[] args) { 186 try { 187 context = new GenericXmlApplicationContext(); 188 context.setValidating(false); 189 context.load("classpath*:applicationContext*.xml"); 190 context.refresh(); 191 dataModuleService = context.getBean(IDataModuleService.class); 192 dataReportService = context.getBean(IDataReportService.class); 193 exec(); 194 if(!IS_LOCAL){ 195 //同步文件夹 196 Runtime.getRuntime().exec(scp_command); 197 } 198 } catch (Exception e) { 199 logger.error("静态化失败", e); 200 } 201 } 202 203 }
4.访问控制,如果存在静态化界面则访问静态化页面
1 @RequestMapping("/index/{moduleId}/{reportId}") 2 public ModelAndView index(@PathVariable Long moduleId, @PathVariable Long reportId) { 3 ModelAndView result = new ModelAndView("main/index"); 4 5 //判断是否静态化 6 if (StaticHtml.existsStatic(moduleId, reportId)) { 7 String static_name = StaticHtml.static_name.replace("${appId}", moduleId.toString()) 8 .replace("${appType}", reportId.toString()).replace(".html", ""); 9 result.setViewName(StaticHtml.static_root+static_name); 10 return result; 11 } 12 //do something 13 return result; 14 }
仅供参考,不足之处还请见谅,欢迎指正!转载请标明出处。如有疑问,欢迎评论或者联系我邮箱1034570286@qq.com