一、重写HTMLLayout

两个自定义类:LzhHTMLLayoutBaseLzhHTMLLayout

LzhHTMLLayoutBase代码如下:

package top.liaozhenghan.logback.study.layout;

import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;

import java.util.Date;
import java.util.HashMap;
import java.util.Map; import com.liaozhenghan.util.dateutil.DateStyle;
import com.liaozhenghan.util.dateutil.DateUtil; import ch.qos.logback.core.Context;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.LayoutBase;
import ch.qos.logback.core.html.CssBuilder;
import ch.qos.logback.core.pattern.Converter;
import ch.qos.logback.core.pattern.ConverterUtil;
import ch.qos.logback.core.pattern.parser.Node;
import ch.qos.logback.core.pattern.parser.Parser;
import ch.qos.logback.core.spi.ScanException; public abstract class LzhHTMLLayoutBase<E> extends LayoutBase<E>{ protected String pattern; protected Converter<E> head; protected String title = "Logback Log Messages"; // It is the responsibility of derived classes to set
// this variable in their constructor to a default value.
protected CssBuilder cssBuilder; // counter keeping track of the rows output
protected long counter = 0; /**
* Set the <b>ConversionPattern </b> option. This is the string which controls
* formatting and consists of a mix of literal content and conversion
* specifiers.
*/
public void setPattern(String conversionPattern) {
pattern = conversionPattern;
} /**
* Returns the value of the <b>ConversionPattern </b> option.
*/
public String getPattern() {
return pattern;
} public CssBuilder getCssBuilder() {
return cssBuilder;
} public void setCssBuilder(CssBuilder cssBuilder) {
this.cssBuilder = cssBuilder;
} /**
* Parses the pattern and creates the Converter linked list.
*/
@Override
public void start() {
int errorCount = 0; try {
Parser<E> p = new Parser<E>(pattern);
p.setContext(getContext());
Node t = p.parse();
this.head = p.compile(t, getEffectiveConverterMap());
ConverterUtil.startConverters(this.head);
} catch (ScanException ex) {
addError("Incorrect pattern found", ex);
errorCount++;
} if (errorCount == 0) {
super.started = true;
}
} protected abstract Map<String, String> getDefaultConverterMap(); /**
* Returns a map where the default converter map is merged with the map
* contained in the context.
*/
public Map<String, String> getEffectiveConverterMap() {
Map<String, String> effectiveMap = new HashMap<String, String>(); // add the least specific map fist
Map<String, String> defaultMap = getDefaultConverterMap();
if (defaultMap != null) {
effectiveMap.putAll(defaultMap);
} // contextMap is more specific than the default map
Context context = getContext();
if (context != null) {
@SuppressWarnings("unchecked")
Map<String, String> contextMap = (Map<String, String>) context.getObject(CoreConstants.PATTERN_RULE_REGISTRY);
if (contextMap != null) {
effectiveMap.putAll(contextMap);
}
}
return effectiveMap;
} /**
* The <b>Title </b> option takes a String value. This option sets the
* document title of the generated HTML document.
*
* <p>
* Defaults to 'Logback Log Messages'.
*/
public void setTitle(String title) {
this.title = title;
} /**
* Returns the current value of the <b>Title </b> option.
*/
public String getTitle() {
return title;
} /**
* Returns the content type output by this layout, i.e "text/html".
*/
@Override
public String getContentType() {
return "text/html";
} /**
* Returns appropriate HTML headers.
*/
@Override
public String getFileHeader() {
StringBuilder sbuf = new StringBuilder();
sbuf.append("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"");
sbuf.append(" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">");
sbuf.append(LINE_SEPARATOR);
sbuf.append("<html>");
sbuf.append(LINE_SEPARATOR);
sbuf.append(" <head>");
sbuf.append(LINE_SEPARATOR);
sbuf.append(" <title>");
sbuf.append(title);
sbuf.append("</title>");
sbuf.append(LINE_SEPARATOR); cssBuilder.addCss(sbuf); sbuf.append(LINE_SEPARATOR);
sbuf.append(" </head>");
sbuf.append(LINE_SEPARATOR);
sbuf.append("<body>");
sbuf.append(LINE_SEPARATOR); return sbuf.toString();
} public String getPresentationHeader() {
StringBuilder sbuf = new StringBuilder();
sbuf.append("<hr/>");
sbuf.append(LINE_SEPARATOR);
sbuf.append("<p><span style='color:red;'>日志启动时间:</span> ");
sbuf.append(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS_CN));
sbuf.append("</p><p></p>");
sbuf.append(LINE_SEPARATOR);
sbuf.append(LINE_SEPARATOR);
sbuf.append("<table cellspacing=\"0\">");
sbuf.append(LINE_SEPARATOR); buildHeaderRowForTable(sbuf); return sbuf.toString();
} private void buildHeaderRowForTable(StringBuilder sbuf) {
Converter c = head;
String name;
sbuf.append("<tr class=\"header\">");
sbuf.append(LINE_SEPARATOR);
while (c != null) {
name = computeConverterName(c);
if (name == null) {
c = c.getNext();
continue;
}
sbuf.append("<td class=\"");
sbuf.append(name);
sbuf.append("\">");
sbuf.append(filterTableTitleName(name));
sbuf.append("</td>");
sbuf.append(LINE_SEPARATOR);
c = c.getNext();
}
sbuf.append("</tr>");
sbuf.append(LINE_SEPARATOR);
} private String filterTableTitleName(String name) { String str = name.toLowerCase();
if ("level".equals(str)) {
name = "级别";
} else if ("date".equals(str)) {
name = "执行时间";
} else if ("callerdata".equals(str)) {
name = "所在行";
} else if ("message".equals(str)) {
name = "信息";
} return name;
} public String getPresentationFooter() {
StringBuilder sbuf = new StringBuilder();
sbuf.append("</table>");
return sbuf.toString();
} /**
* Returns the appropriate HTML footers.
*/
@Override
public String getFileFooter() {
StringBuilder sbuf = new StringBuilder();
sbuf.append(LINE_SEPARATOR);
sbuf.append("</body></html>");
return sbuf.toString();
} protected void startNewTableIfLimitReached(StringBuilder sbuf) {
if (this.counter >= CoreConstants.TABLE_ROW_LIMIT) {
counter = 0;
sbuf.append("</table>");
sbuf.append(LINE_SEPARATOR);
sbuf.append("<p></p>");
sbuf.append("<table cellspacing=\"0\">");
sbuf.append(LINE_SEPARATOR);
buildHeaderRowForTable(sbuf);
}
} protected String computeConverterName(Converter c) { String name = null; String className = c.getClass().getSimpleName();
int index = className.indexOf("Converter");
if (index == -1) {
name = className;
} else {
name = className.substring(0, index);
} return name;
} }

LzhHTMLLayout代码如下:

package top.liaozhenghan.logback.study.layout;

import static ch.qos.logback.core.CoreConstants.LINE_SEPARATOR;

import java.util.Map;

import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.html.DefaultCssBuilder;
import ch.qos.logback.classic.html.DefaultThrowableRenderer;
import ch.qos.logback.classic.pattern.MDCConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.helpers.Transform;
import ch.qos.logback.core.html.IThrowableRenderer;
import ch.qos.logback.core.pattern.Converter; public class LzhHTMLLayout extends LzhHTMLLayoutBase<ILoggingEvent>{ /**
* Default pattern string for log output.
*/
static final String DEFAULT_CONVERSION_PATTERN = "%date{HH:mm:ss}%level%caller{1}%msg"; IThrowableRenderer<ILoggingEvent> throwableRenderer; /**
* Constructs a PatternLayout using the DEFAULT_LAYOUT_PATTERN.
*
* The default pattern just produces the application supplied message.
*/
public LzhHTMLLayout() {
pattern = DEFAULT_CONVERSION_PATTERN;
throwableRenderer = new DefaultThrowableRenderer();
cssBuilder = new DefaultCssBuilder();
} @Override
public void start() {
int errorCount = 0;
if (throwableRenderer == null) {
addError("ThrowableRender cannot be null.");
errorCount++;
}
if (errorCount == 0) {
super.start();
}
} protected Map<String, String> getDefaultConverterMap() {
return PatternLayout.defaultConverterMap;
} public String doLayout(ILoggingEvent event) {
StringBuilder buf = new StringBuilder();
startNewTableIfLimitReached(buf); boolean odd = true;
if (((counter++) & 1) == 0) {
odd = false;
} String level = event.getLevel().toString().toLowerCase(); buf.append(LINE_SEPARATOR);
buf.append("<tr class=\"");
buf.append(level);
if (odd) {
buf.append(" odd\">");
} else {
buf.append(" even\">");
}
buf.append(LINE_SEPARATOR); Converter<ILoggingEvent> c = head;
while (c != null) {
appendEventToBuffer(buf, c, event);
c = c.getNext();
}
buf.append("</tr>");
buf.append(LINE_SEPARATOR); if (event.getThrowableProxy() != null) {
throwableRenderer.render(buf, event);
}
return buf.toString();
} private void appendEventToBuffer(StringBuilder buf, Converter<ILoggingEvent> c, ILoggingEvent event) {
buf.append("<td class=\"");
buf.append(computeConverterName(c));
buf.append("\">");
buf.append(Transform.escapeTags(c.convert(event)));
buf.append("</td>");
buf.append(LINE_SEPARATOR);
} public IThrowableRenderer getThrowableRenderer() {
return throwableRenderer;
} public void setThrowableRenderer(IThrowableRenderer<ILoggingEvent> throwableRenderer) {
this.throwableRenderer = throwableRenderer;
} @Override
protected String computeConverterName(Converter c) {
if (c instanceof MDCConverter) {
MDCConverter mc = (MDCConverter) c;
String key = mc.getFirstOption();
if (key != null) {
return key;
} else {
return "MDC";
}
} else {
return super.computeConverterName(c);
}
}
}

二、logback.xml配置


<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="3 seconds">
<!-- 定义变量 -->
<if condition='p("os.name").contains("Windows")'>
<then>
<property name="LOG_PATH" value="c:/logs" />
</then>
</if>
<if condition='p("os.name").contains("Linux")'>
<then>
<property name="LOG_PATH" value="logs" />
</then>
</if>
<property name="APP_NAME" value="study" />
<property name="LOG_ROOT_LEVEL" value="debug" />
<property name="maxHistory" value="30" /> <contextName>${APP_NAME}</contextName> <appender name="STDOUT"
class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>
<!-- 设置日志输出格式 -->
[%-5level] %d{yyyy-MM-dd HH:mm:ss} [%thread] %logger{36} - %m%n
</pattern>
</encoder>
</appender> <!-- 按照每天生成日志文件 -->
<appender name="FILE_ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}/ERROR.log</file>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/${APP_NAME}/ERROR.%d.log
</FileNamePattern>
<MaxHistory>${maxHistory}</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> <appender name="FILE_WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}/WARN.log</file>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/${APP_NAME}/WARN.%d.log
</FileNamePattern>
<MaxHistory>${maxHistory}</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> <appender name="FILE_INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}/INFO.log</file>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/${APP_NAME}/INFO.%d.log
</FileNamePattern>
<MaxHistory>${maxHistory}</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> <appender name="FILE_DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOG_PATH}/${APP_NAME}/DEBUG.log</file>
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<layout class="top.liaozhenghan.logback.study.layout.LzhHTMLLayout"/>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${LOG_PATH}/${APP_NAME}/DEBUG.%d.log
</FileNamePattern>
<MaxHistory>${maxHistory}</MaxHistory>
</rollingPolicy>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender> <root level="${LOG_ROOT_LEVEL}">
<!-- 控制台输出 -->
<appender-ref ref="STDOUT" />
<!-- 文件输出 -->
<appender-ref ref="FILE_ERROR" />
<appender-ref ref="FILE_WARN" />
<appender-ref ref="FILE_INFO" />
<appender-ref ref="FILE_DEBUG" />
</root>
</configuration>

logback.xml


三、查看日志的jsp页面

用了三个页面:登录页面loglogin.jsp,日志级别选择页面logselect.jsp,日志显示页面log.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>日志系统登录</title>
<meta charset="UTF-8">
<!-- meta信息,可维护 -->
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-touch-fullscreen" content="yes"> </head>
<body style="width: 100%;"> <form action="" method="post">
<p>密码:</p><input name="password"><br>
<input type="submit" value="登录日志系统">
</form>
</body>
</html>

loglogin.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html>
<html lang="en">
<head>
<title>日志记录</title>
<meta charset="UTF-8">
<!-- meta信息,可维护 -->
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=no">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-touch-fullscreen" content="yes">
<script src="js/jquery.min.js" type="text/javascript"></script> <style type="text/css">
.lzh_div td{
}
</style> </head>
<body style="width: 100%;"> <form action="" method="post">
<input id="date" type="date" name="date">
<select id="levels" name="level">
<!-- <option value="TRACE">TRACE</option> -->
<option value="DEBUG">DEBUG</option>
<option value="INFO">INFO</option>
<option value="WARN">WARN</option>
<option value="ERROR">ERROR</option>
</select>
<input type="submit" value="查看日志">
</form>
<script type="text/javascript">
var level = "${level}";
var date = "${date}";
$("#levels").val(level);
$("#date").val(date);
</script>
<div class="lzh_div" style="width: 100%;">${html}</div>
</body>
</html>

logselect.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isELIgnored="false"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
${html}

log.jsp

四、LogController.java

package top.liaozhenghan.logback.study.controller;

import java.io.File;
import java.io.IOException;
import java.util.Date; import javax.servlet.http.HttpServletRequest; import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping; import com.liaozhenghan.util.dateutil.DateStyle;
import com.liaozhenghan.util.dateutil.DateUtil;
import com.liaozhenghan.util.httputil.SrcUtil; @Controller
public class LogController { final static Logger LOG = LoggerFactory.getLogger(LogController.class);
final static String LOG_LOGIN = "LOG_LOGIN"; @RequestMapping(value="/log")
public String log(HttpServletRequest request, Model model) { String date = request.getParameter("date");
String level = request.getParameter("level");
String password = request.getParameter("password");
String html = null; // 判断是否登录
Object login = request.getSession().getAttribute(LOG_LOGIN);
if (login == null) {
String PASSWORD = "baofa2018"; if (PASSWORD.equals(password)) {
request.getSession().setAttribute(LOG_LOGIN, LOG_LOGIN);
} else {
return "logs/loglogin";
}
} // 1.判断参数是否为空
if (StringUtils.isEmpty(level) && StringUtils.isEmpty(date)) {
date = DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD);
level = "ERROR";
model.addAttribute("date", date);
model.addAttribute("level", level);
return "logs/logselect";
} // 2.判断路径
String filepath = "c:/logs/study/";
String osName = System.getProperty("os.name");
if (StringUtils.isEmpty(osName)) {
html = "系统错误";
model.addAttribute("date", date);
model.addAttribute("level", level);
model.addAttribute("html", html);
return "logs/logselect";
} else if (osName.contains("Window")) {
filepath = "c:/logs/study/";
} else if (osName.contains("Linux")) {
filepath = "logs/study/";
} else {
html = "未识别的操作系统:" + osName;
model.addAttribute("date", date);
model.addAttribute("level", level);
model.addAttribute("html", html);
return "logs/logselect";
} if (StringUtils.isNotEmpty(date) && !DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD).equals(date)) {
filepath += level + "." + date + ".log";
} else {
filepath += level + ".log";
date = DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD);
} File file = new File(filepath);
html = "无日志记录";
if (file.exists()) {
try {
html = FileUtils.readFileToString(file, "UTF-8");
} catch (IOException e) {
LOG.error(DateUtil.DateToString(new Date(), DateStyle.YYYY_MM_DD_HH_MM_SS)
+ "【文件名】" + filepath, e);
}
} LOG.debug("测试");
LOG.info("测试");
LOG.warn("测试");
LOG.error("测试"); model.addAttribute("html", html);
model.addAttribute("date", date);
model.addAttribute("level", level);
return "logs/log";
}
}

注:logback.xml在tomcat环境下的日志目录可改为:

<property name="LOG_PATH" value="${catalina.base}/logs" />

在java代码中获取文件目录改为:

String catalina_base = System.getProperty("catalina.base");
String filepath = catalina_base + "/logs/study/";

springmvc+logback项目的日志搭建的更多相关文章

  1. 微信开发准备(二)--springmvc+mybatis项目结构的搭建

    转自:http://www.cuiyongzhi.com/post/34.html 前面一篇有说道如何在MyEclipse中搭建maven项目,这里将继续介绍如何在搭建好的基础maven项目中引入我们 ...

  2. IDEA中maven搭建Spring+SpringMVC+mybatis项目

    一.介绍 使用IDEA搭建maven web项目,整合框架Spring+SpringMVC+mybatis 项目结构图:

  3. Spring+SpringMVC+Mybatis+MAVEN+Eclipse+项目完整环境搭建

    1.新建一个Maven项目,创建父项目. 2.创建子项目模块 3.创建javaWeb项目 4.创建后的项目目录结构 5.Maven文件配置 parent父项目pom.xml文件配置 <?xml ...

  4. 脚手架快速搭建springMVC框架项目

    apid-framework脚手架快速搭建springMVC框架项目   rapid-framework介绍:   一个类似ruby on rails的java web快速开发脚手架,本着不重复发明轮 ...

  5. rapid-framework脚手架快速搭建springMVC框架项目

    rapid-framework介绍:   一个类似ruby on rails的java web快速开发脚手架,本着不重复发明轮子的原则,框架只是将零散的struts(struts2)+spring+h ...

  6. 从头开始基于Maven搭建SpringMVC+Mybatis项目(2)

    接上文内容,本节介绍Maven的聚合和继承. 从头阅读传送门 互联网时代,软件正在变得越来越复杂,开发人员通常会对软件划分模块,以获得清晰的设计.良好的分工及更高的可重用性.Maven的聚合特性能把多 ...

  7. IDEA 搭建 springmvc maven 项目

    前言:将搭建 java springmvc maven 项目的过程及问题记录下来,以及配置文件.这次没有涉及到数据库,后续再写. 目录: 一.首先在 IDEA 中创建 springmvc maven ...

  8. 解决:springmvc maven 项目搭建完后没有src目录,而且maven导入很慢

    前言:在搭建springmvc maven项目中遇到的问题做总结,比如搭建后没有src,同时这里也解决了搭建后maven导入很慢的问题. 问题: 1.发现创建出来的maven项目没有src文件 ,而且 ...

  9. Docker 搭建 ELK 读取微服务项目的日志文件

    思路: 在docker搭建elasticsearch与kibana来展示日志,在微服务部署的机子上部署logstash来收集日志传到elasticsearch中,通过kibana来展示,logstas ...

随机推荐

  1. How to Pronounce the 50 States

    How to Pronounce the 50 States (1/4) Share Tweet Share Tagged With: Places The US state names can be ...

  2. 迷你MVVM框架 avalonjs1.5.2 发布

    经过2个小版本的试水, avalon1.5这个全新的架构也终于成熟了. 首先是组件的配置项,名字改了不少,让大家都满意. ms-duplex, ms-include, ms-if等指令的BUG修复. ...

  3. OPENWRT路由3G拔号实验

    以下摘自:http://www.right.com.cn/forum/thread-155168-1-1.html 首先下载 Barrier Breaker 14.07 固件 配置好网络,可以访问到i ...

  4. Bug : Cannot evaluate ...toString()

  5. [转载]FMS Dev Guide学习笔记(验证用户)

    一.开发交互式的媒体应用程序 1.使用外部资源验证用户 对于有限数量的客户,请求用户名密码,然后通过外部资源(像数据库.LDAP服务或其它访问授权服务)验证它们,是可行的.     a.SWF在请求连 ...

  6. 如何使用CBO,CBO与RULE的区别

    Oracle的优化器有两种优化方式,即基于规则的优化方式(Rule-Based Optimization,简称为RBO)和基于代价的优化方式(Cost-Based Optimization,简称为CB ...

  7. vue-router,vuex

    vue设置路由为了服务器渲染今天换另一种方式首先在文件夹中router建立router和routes两个js文件,router用来设置路由,routes用来建立路由代码如下: router: impo ...

  8. SAP 000 客户端初始登录

    Solution 在SAP系统DB中删除账号SAP*,SAP系统会自动创建SAP*这个账号,然后初始密码是“PASS”,这样就获得Client 000 SAP*账号. Step by Step 以Or ...

  9. 目前为止最全的微信小程序项目实例

    https://blog.csdn.net/zuoliangzhu/article/details/53862576#t1

  10. nginx反向代理:两个域名指向不同web服务端口

    一台服务器上安装了zabbix服务和jumpserver服务,两个域名zabbix.xxxx.xxxx和jumserver.xxx.xxxx 一.编辑/etc/nginx/conf.d目录下nginx ...