本文参考:
http://www.cnblogs.com/tony-zt/p/9260017.html
http://www.importnew.com/12707.html
https://blog.csdn.net/wzy18210825916/article/details/80946454
https://blog.csdn.net/column/details/17959.html
https://www.2cto.com/database/201708/668379.html
感谢以上分享的作者。
本篇为Solr7.4版本 + windows10系统为案例进行配置和部署。通过本篇内容小白都可以掌握Solr的基本使用方法,get新技能。
系统要求:
JDK 1.8以上
一、“安装”
从官网下载Solr7.4(或本资源包内直接解压,本包内也是官网下载的)
下载地址:https://mirrors.tuna.tsinghua.edu.cn/apache/lucene/solr/7.4.0/
因为我是Windows系统所以选的是.zip的版本,如果是Linux系统需要用.tgz的版本,下面都是以Windows系统下的示例。
Solr7.4是免安装的,解压后就可以直接使用了。
win+R,在打开输入栏:输入 cmd ,点确定,弹出命令提示符窗口
在窗口中输入你的Solr安装的盘符加冒号,比如 D:回车
然后再输入:cd 你的Solr安装路径一直到bin文件夹,
比如我的是: D:\Work_Space\Solr\solr-7.4.0\bin
回车,然后再输入:solr start
会出现下面的信息,7.4的里面会有一些错误信息,但不影响使用。6.6版本的没有,6.6版本的配置方法和7.4是完全一样的。如果有强迫症的可以使用6.6.0或6.6.1(其他的没试过)
Solr的默认端口号是8983
启动成功后,可以用浏览器验证一下:
地址栏输入:http://localhost:8983/solr
就会出现Solr控制台主页面:
提前声明一下,Solr7.4是自带Jetty服务器的,不需要集成到Tomcat服务器中。反正我是不会这么做,因为分离开方便后期维护,如果想要修改Solr的配置也不需要停掉项目。所以,为什么要部署到Tomcat?不啰嗦了,自己看吧。
二、创建core
在cmd窗口输入: solr create -c testcore
testcore 是自己起的名字,回车后会出现下面的信息(还是会有log4j2的错误信息,不用管)
我们刷新一下控制台可以看到:
点击Core Selector,选择刚刚创建的testcore,可以看到如下界面:
Core也可以直接在控制台创建,但是需要自己先再Solr安装根目录/server/solr目录下创建一个core文件夹,而且里面要自己创建一个data文件夹。然后通过控制台的Core Admin创建core 。
个人建议直接在cmd窗口用命令创建,省力省心还可靠。
网上还有自己拷贝conf文件夹到自己创建core 等等的操作,感觉太麻烦。有兴趣的自行百度。
三、配置core索引MySQL数据
1、把数据库驱动jar包放到
Solr安装根目录/server/solr-webapp/webapp/WEB-INF/lib下
2、把Solr安装根目录/dist文件夹下的
solr-dataimporthandler-x.x.x.jar
solr-dataimporthandler-extras-x.x.x.jar
放到Solr安装根目录/server/solr-webapp/webapp/WEB-INF/lib下
3、Solr安装根目录/server/solr/核心/conf路径下添加文件data-config.xml,并添加以下内容(示范如下)
3.1全量索引
<dataConfig >
<dataSource driver ="com.mysql.jdbc.Driver" url ="jdbc:mysql://127.0.0.1:3306/solrdb" user ="root" password ="123456" />
<document >
<entity name ="testdb" pk ="tid" query ="select * from testdb" >
<field column ="tid" name ="idid" />
<field column ="tname" name ="TName" />
<field column ="tbirthday" name ="TBirthDay" />
</entity >
</document >
</dataConfig >
3.2增量索引(含同时具有全量和增量索引的功能)
可以直接配置这一个跳过3.1,上面3.1的配置是为了能让你区别全量和增量配置的不同之处。
3.2.1
solr默认使用UTC时间,即与中国时差8小时,所以需要修改配置文件:
Solr安装根目录/bin/solr.in.sh
SOLR_TIMEZONE=”UTC+8”
默认是注释掉的,找到SOLR_TIMEZONE修改后面的值为UTC+8
注意:如果单纯修改solr.in.sh文件没有作用,就修改和solr.in.sh同目录下的solr.cmd文件,修改其中的set SOLR_TIMEZONE=UTC为set SOLR_TIMEZONE=UTC+8
3.2.2
修改mysql数据库的表结构,添加一个时间戳字段,当某行数据发生更新时该字段自动更新为修改数据的时间,为solr增量添加提供服务(范例如下)
ALTER TABLE testdb ADD last_modified TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP DEFAULT current_timestamp
3.2.3
修改solr/server/solr/核心/conf路径下添加文件data-config.xml,并添加增量SQL(示范如下)
就是多添加了deltaQuery部分
<dataConfig >
<dataSource driver ="com.mysql.jdbc.Driver" url ="jdbc:mysql://127.0.0.1:3306/solrdb" user ="root" password ="123456" />
<document >
<entity name ="testdb" pk ="tid" query ="select * from testdb"
deltaQuery ="select tid from testdb where last_modified > '${dih.last_index_time}'" >
<field column ="tid" name ="idid" />
<field column ="tname" name ="TName" />
<field column ="tbirthday" name ="TBirthDay" />
</entity >
</document >
</dataConfig >
4、修改solrconfig.xml,添加以下内容
data-config.xml
5、修改managed-schema,添加mysql中需要存入solr的字段(示范如下)
准备测试效果:
数据库里的数据:
注意:当last_modified的值是0000-00-00 00:00:00时会有错误,
因为java的时间是从1970年开始的,所以不能翻译这个时间,导致的结果就是查不到数据。
现在测试全量更新:依次选择1234
结果是:
测试增量更新,在数据库新添一条数据
注意:增量更新就是只更新有变化的数据,不会更新没有变化的数据。如果增量更新选择clean会删除所有的原索引数据,然后只更新有修改过的数据。
正常使用情况下增量更新的clean是不选择的。这里为了测试更新方式是增量更新的方式,所以选择了clean。切忌用在项目中!!!除非你知道会有什么后果
结果是:
我们看到,之前的两条数据被删除了,只有一条新添加的数据。证明增量更新的功能有效。
四、接下来我们配置一个实用的功能:定时更新
因为数据库的数据可能是动态变化的,为了能和数据库的数据“及时”同步,所以就有了这个功能。
它可以按设定时间自动更新一次索引
4.1修改testcore目录下的配置文件core.properties
name=testcore
config=solrconfig.xml
schema=data-config.xml
dataDir=data
4.2添加实时更新索引相关的jar包:dataimportscheduler-1.2.jar 到
Solr安装根目录/server/solr-webapp/webapp/WEB-INF/lib下
还有两个jar包因为之前已经添加过了就不需要添加了,是
solr-dataimporthandler-x.x.x.jar
solr-dataimporthandler-extras-x.x.x.jar
4.3 修改Solr安装根目录/server/solr-webapp/webapp/WEB-INF/web.xml
把这个添加到里面
org.apache.solr.handler.dataimport.scheduler.ApplicationListener
注意:中间的内容两边不要有空格,容易出现不正常现象
4.4添加更新配置文件:Solr安装根目录/server/solr下新建conf文件夹
在文件夹下新建dataimport.properties文件
#################################################
# #
# dataimport scheduler properties #
# #
#################################################
# to sync or not to sync
# 1 - active; anything else - inactive
syncEnabled=1
# which cores to schedule
# in a multi-core environment you can decide which cores you want syncronized
# leave empty or comment it out if using single-core deployment
#syncCores=game,resource
syncCores=testcore
# solr server name or IP address
# [defaults to localhost if empty]
server=localhost
# solr server port
# [defaults to 80 if empty]
port=8983
interval=2
# application name/context
# [defaults to current ServletContextListener's context (app) name]
webapp=solr
# URL params [mandatory]
# remainder of URL
params=/dataimport?command=delta-import&clean=false &commit=true
# schedule interval
# number of minutes between two runs
# [defaults to 30 if empty]
# 重做索引的时间间隔,单位分钟,默认7200,即5天;
# 为空,为0,或者注释掉:表示永不重做索引
reBuildIndexInterval=7200
# 重做索引的参数
reBuildIndexParams=/dataimport?command=full-import&clean=true &commit=true
# 重做索引时间间隔的计时开始时间,第一次真正执行的时间=reBuildIndexBeginTime+reBuildIndexInterval*60*1000;
# 两种格式:2012-04-11 03:10:00 或者 03:10:00,后一种会自动补全日期部分为服务启动时的日期
reBuildIndexBeginTime=03 :10 :00
测试定时更新
我们先全量更新一下所有数据,然后在数据库添加一条数据,再等一分钟直接查询
更新前
更新后
五、配置中文分词
solr自带的几个分词器对中文支持并不好,所以需要使用第三方分词器对中文进行分词索引。
常用的分词器有:ansj和ik,前者的效果更好。
注:目前发现ansj分词器索引内容大小超过65248字节时,会报异常,目前尚未找到解决办法
5.1需要的jar包:
ansj_lucene5_plug-5.1.1.2.jar
ansj_seg-5.1.1.jar
ik-analyzer-solr5-5.x.jar
nlp-lang-1.7.2.jar
放到Solr安装根目录/server/solr-webapp/webapp/WEB-INF/lib 中
5.2配置放到Solr安装根目录/server/solr/testcore/conf下的managed-schema
(还是之前配置的那个)
<fieldType name ="text_ik" class ="solr.TextField" >
<analyzer type ="index" >
<tokenizer class ="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart ="false" />
</analyzer >
<analyzer type ="query" >
<tokenizer class ="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart ="true" />
<filter class ="solr.SynonymFilterFactory" synonyms ="synonyms.txt" ignoreCase ="true" expand ="true" />
</analyzer > </fieldType >
<fieldType name ="text_ansj" class ="solr.TextField" positionIncrementGap ="100" >
<analyzer type ="index" >
<tokenizer class ="org.ansj.lucene.util.AnsjTokenizerFactory" isQuery ="false" stopwords ="/path/to/stopwords.dic" />
</analyzer >
<analyzer type ="query" >
<tokenizer class ="org.ansj.lucene.util.AnsjTokenizerFactory" stopwords ="/path/to/stopwords.dic" />
</analyzer >
</fieldType >
然后为要索引的字段添加分词器,例如
<field name="TName" type ="text_ansj" indexed="true" stored="true" />
测试
成功了!
SolrJ 操作索引的增、删、查
import org.apache .solr .client .solrj .SolrClient
import org.apache .solr .client .solrj .SolrQuery
import org.apache .solr .client .solrj .SolrServerException
import org.apache .solr .client .solrj .impl .HttpSolrClient
import org.apache .solr .client .solrj .response .QueryResponse
import org.apache .solr .common .SolrDocument
import org.apache .solr .common .SolrDocumentList
import org.apache .solr .common .SolrInputDocument
import java.io .IOException
import java.util .Iterator
public class IndexOperation {
private static final String urlString = "http://localhost:8983/solr/testcore"
private static SolrClient solr = new HttpSolrClient.Builder (urlString).build ()
public void addIndexTest(){//添加一个索引
SolrInputDocument doc = new SolrInputDocument()
//默认id为主键,当id存在时更新数据,否则添加数据
doc.addField ("id" , "3" )
doc.addField ("name" , "hello world test" )
doc.addField ("age" , "230" )
doc.addField ("addr" , "1111" )
try {
solr.add (doc)
solr.commit ()
} catch (SolrServerException e) {
e.printStackTrace ()
} catch (IOException e) {
e.printStackTrace ()
}
}
public void deleteIndexTest(String did){
//通过id删除索引
try {
solr.deleteById (did)
solr.commit ()
} catch (SolrServerException e) {
e.printStackTrace ()
} catch (IOException e) {
e.printStackTrace ()
}
//通过搜索条件删除索引
//solr.deleteByQuery (query)
}
public void selectIndexTest(){// 查询
SolrQuery query = new SolrQuery()
// *标示多个任意字符,?标示单个任意字符,~模糊搜索
query.setQuery ("*:*" )
// 分页
query.setStart (0 )
query.setRows (10 )
QueryResponse queryResponse = null
try {
queryResponse = solr.query (query)
} catch (SolrServerException e) {
e.printStackTrace ()
} catch (IOException e) {
e.printStackTrace ()
}
SolrDocumentList docs = queryResponse.getResults ()
Iterator<SolrDocument> iter = docs.iterator ()
while(iter.hasNext ()){
SolrDocument doc = iter.next ()
System.out .println (doc.toString ())
}
try {
solr.commit ()
} catch (SolrServerException e) {
e.printStackTrace ()
} catch (IOException e) {
e.printStackTrace ()
}
}
//测试
public static void main(String[] args){
IndexOperation ion=new IndexOperation()
ion.addIndexTest ()
ion.selectIndexTest ()
System.out .println ("---------------分割线-----------------" )
ion.deleteIndexTest ("3" )
ion.selectIndexTest ()
}
}
运行结果:
七、通过SolrJ对MySQL数据库进行全量更新、增量更新
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
public class LinkMysql {
private CloseableHttpClient httpclient = null ;
private CookieStore cookieStore = null ;
private final String baseSolrUrl;
/**
* 全量导入
*/
private static final String FULL_IMPORT = "full-import" ;
/**
* 增量导入
*/
private static final String DELTA_IMPORT = "delta-import" ;
public LinkMysql (String baseSolrUrl) {
if (!baseSolrUrl.endsWith("/" )){
baseSolrUrl += "/" ;
}
this .baseSolrUrl = baseSolrUrl;
}
private synchronized void init (){
if (httpclient == null ){
cookieStore = new BasicCookieStore();
httpclient = HttpClientBuilder.create().setDefaultCookieStore(cookieStore).build();
}
}
public void fullImport (String coreName) throws IOException {
init();
HttpPost post = getDataImportPost(coreName, FULL_IMPORT);
httpclient.execute(post);
}
public void deltaImport (String coreName) throws IOException {
init();
HttpPost post = getDataImportPost(coreName, DELTA_IMPORT);
httpclient.execute(post);
}
private HttpPost getDataImportPost (String coreName,String command) throws UnsupportedEncodingException{
HttpPost post = new HttpPost(baseSolrUrl + coreName + "/dataimport?indent=on&wt=json&_=" + new Date().getTime());
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("command" , command));
params.add(new BasicNameValuePair("verbose" , "false" ));
if (command.equals(FULL_IMPORT)){
params.add(new BasicNameValuePair("clean" , "true" ));
}
params.add(new BasicNameValuePair("commit" , "true" ));
params.add(new BasicNameValuePair("optimize" , "false" ));
params.add(new BasicNameValuePair("core" , coreName));
params.add(new BasicNameValuePair("name" , "dataimport" ));
post.setEntity(new UrlEncodedFormEntity(params, "UTF-8" ));
return post;
}
public void close () throws IOException{
httpclient.close();
httpclient = null ;
cookieStore = null ;
}
public static void main (String[] args){
LinkMysql dataClient=new LinkMysql("http://localhost:8983/solr/" );
try {
dataClient.fullImport("testcore" );
dataClient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
八、索引高亮显示
需要有一个实体类
public class TXDocument {
private String id;
private String path;
private String content;
public String getId () {
return id;
}
public void setId (String id) {
this .id = id;
}
public String getPath () {
return path;
}
public void setPath (String path) {
this .path = path;
}
public String getContent () {
return content;
}
public void setContent (String content) {
this .content = content;
}
public String toString () {
return "TXDocument{" +
"id='" + id + '\'' +
", path='" + path + '\'' +
", content='" + content + '\'' +
'}' ;
}
}
下面来高亮的代码
import org.apache .solr .client .solrj .SolrQuery
import org.apache .solr .client .solrj .SolrServerException
import org.apache .solr .client .solrj .impl .HttpSolrClient
import org.apache .solr .client .solrj .response .QueryResponse
import org.apache .solr .common .SolrDocument
import org.apache .solr .common .SolrDocumentList
import java.io .IOException
import java.util .List
import java.util .Map
public class GaoLiang {
public void setHighL(){
HttpSolrClient solrClient = new HttpSolrClient.Builder ("http://127.0.0.1:8983/solr/testcore" ).build ()
SolrQuery query = new SolrQuery()
query.set ("q" ,"TName:*回归*" )
//1. 过滤器
//query.set ("fq" ,"pprice:[1 TO 100]" )
//2. 排序
//query.set ("sort" ,"pprice desc,id asc" )
//3. 设置查询到的文档返回的域对象
//query.set ("fl" ,"TBPackageName,PackageTypeID" )
//4. 设置默认查询的域
//query.set ("df" ,"pname" )
//5. 分页
//query.set ("start" ,0 )
//query.set ("rows" ,5 )
//6. 高亮
//query.set ("hl" ,true)
//设置高亮域(设置的域必须在查询条件中存在)
// query.set ("h1.fl" ,"TBPackageName" )
//前缀
// query.set ("hl.simple.pre" ,"<em style='color:red'>" )
//后缀
//query.set ("hl.simple.post" ,"</em>" )
query.setHighlight (true)
query.addHighlightField ("TName" )
query.setHighlightSimplePre ("<em style='color:red'>" )
query.setHighlightSimplePost ("</em>" )
QueryResponse response=null
{
try {
response = solrClient.query (query)
} catch (SolrServerException e) {
e.printStackTrace ()
} catch (IOException e) {
e.printStackTrace ()
}
}
SolrDocumentList results = response.getResults ()
System.out .println (results)
//k是id,内部的map的key是域名,其value是高亮的值集合
Map<String, Map<String, List<String>>> highlighting = response.getHighlighting ()
System.out .println ("匹配的结果总数是-------" +results.getNumFound ())
for(SolrDocument document:results) {
System.out .println ("id----" + document.get ("id" ))
System.out .println ("pname-----" + document.get ("TName" ))
//System.out .println ("pprice------" + document.get ("pprice" ))
List<String> list = null
if(highlighting.get (document.get ("id" )) != null) {
list = highlighting.get (document.get ("id" )).get ("TName" )
}else {
System.out .println ("无法获取高亮map" )
}
System.out .println (list)
if (list != null && list.size () > 0 ) {
System.out .println ("高亮显示的内容:----" +list.get (0 ))
}else {
System.out .println ("高亮显示的内容为空!!!" )
}
System.out .println ("=========================" )
}
}
public static void main(String[] args){
GaoLiang gl=new GaoLiang()
gl.setHighL ()
}
}
运行后的结果:
如果之前你对高亮怎么用在前台显示的文字里,看到这个结果你应该能够猜到了,就是给需要高亮的字段加上了html标签,至于加什么效果,用什么标签就自己决定吧。高亮的意思不是闪闪发亮,只是一个让查询字段特别显示的代名词。
把这个以字符串的形式传给前台……后面就不需要我啰嗦了吧。
九、SolrJ读取富文本创建索引
就是读取word、pdf、xml……等文件的内容创建索引
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class FuWenBen {
public static void main (String[] args)
{
beStart("solr-word.pdf" );
}
public static void beStart (String fname){
String fileUrl = "E:/WorkSpace/ImportData/" +fname;
try
{
indexFilesSolrCell(fname, fname,fileUrl);
}
catch (IOException e)
{
e.printStackTrace();
}
catch (SolrServerException e)
{
e.printStackTrace();
}
}
/**
* @Author :sks
* @Description :获取系统当天日期yyyy-mm-dd
* @Date :
*/
private static String GetCurrentDate (){
Date dt = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd" );
String day =sdf.format(dt);
return day;
}
public static void indexFilesSolrCell (String fileName, String solrId, String path)
throws IOException, SolrServerException
{
String urlString = "http://localhost:8983/solr/testcore" ;
SolrClient solr = new HttpSolrClient.Builder(urlString).build();
ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update/extract" );
String contentType = getFileContentType(fileName);
up.addFile(new File(path), contentType);
String fileType = fileName.substring(fileName.lastIndexOf("." )+1 );
up.setParam("literal.id" , fileName);
up.setParam("literal.path" , path);
up.setParam("literal.pathuploaddate" , GetCurrentDate());
up.setParam("literal.pathftype" , fileType);
up.setParam("fmap.content" , "attr_content" );
up.setAction(AbstractUpdateRequest.ACTION.COMMIT, true , true );
solr.request(up);
}
/**
* @Author :sks
* @Description :根据文件名获取文件的ContentType类型
* @Date :
*/
public static String getFileContentType (String filename) {
String contentType = "" ;
String prefix = filename.substring(filename.lastIndexOf("." ) + 1 );
if (prefix.equals("xlsx" )) {
contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ;
} else if (prefix.equals("pdf" )) {
contentType = "application/pdf" ;
} else if (prefix.equals("doc" )) {
contentType = "application/msword" ;
} else if (prefix.equals("txt" )) {
contentType = "text/plain" ;
} else if (prefix.equals("xls" )) {
contentType = "application/vnd.ms-excel" ;
} else if (prefix.equals("docx" )) {
contentType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ;
} else if (prefix.equals("ppt" )) {
contentType = "application/vnd.ms-powerpoint" ;
} else if (prefix.equals("pptx" )) {
contentType = "application/vnd.openxmlformats-officedocument.presentationml.presentation" ;
}
else {
contentType = "othertype" ;
}
return contentType;
}
}
测试结果:内容太长,就截取了一部分,证明代码是成功的。
十、总结与说明
本文内容都已经测试通过,如有效果与文中不一致,可以解压solr样本对比配置内容。
注意:
为了验证时区调整,demo中修改了solr.cmd(set SOLR_TIMEZONE=UTC+8)
但这会让增量更新出现一个错误,就是更新数据后原数据不能被删除。没找到更好的解决办法。
如果其他地方不需要用这个时间,就不用设置solr.cmd了。
这样dataconfig.properties中的时间和我们的时间差8个小时,但是不影响使用。
暂时先不再深入了。毕竟我连个软件开发工作都找不到,还瞎操什么心。不说了,搬砖去了。
Demo和jar包下载可以到uponhead.com 去下,搜索solr就能找到了。是免费的。
如果觉得内容可以的话打赏点小费呗,让楼主吃饭的时候能多加一袋咸菜,搬砖真的很累的。
本Markdown编辑器使用StackEdit 修改而来,用它写博客,将会带来全新的体验哦:
Markdown和扩展Markdown简洁的语法
代码块高亮
图片链接和图片上传
LaTex 数学公式
UML序列图和流程图
离线写博客
导入导出Markdown文件
丰富的快捷键
快捷键
加粗 Ctrl + B
斜体 Ctrl + I
引用 Ctrl + Q
插入链接 Ctrl + L
插入代码 Ctrl + K
插入图片 Ctrl + G
提升标题 Ctrl + H
有序列表 Ctrl + O
无序列表 Ctrl + U
横线 Ctrl + R
撤销 Ctrl + Z
重做 Ctrl + Y
Markdown及扩展
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档,然后转换成格式丰富的HTML页面。 —— [ 维基百科 ]
使用简单的符号标识不同的标题,将某些文字标记为粗体 或者斜体 ,创建一个链接 等,详细语法参考帮助?。
本编辑器支持 Markdown Extra , 扩展了很多好用的功能。具体请参考Github .
表格
Markdown Extra 表格语法:
项目
价格
Computer
$1600
Phone
$12
Pipe
$1
可以使用冒号来定义对齐方式:
项目
价格
数量
Computer
1600 元
5
Phone
12 元
12
Pipe
1 元
234
定义列表
Markdown Extra 定义列表语法:
项目1
项目2
定义 A
定义 B
项目3
定义 C
定义 D
定义D内容
代码块
代码块语法遵循标准markdown代码,例如:
@requires_authorization
def somefunc (param1='' , param2=0 ) :
'''A docstring'''
if param1 > param2:
print 'Greater'
return (param2 - param1 + 1 ) or None
class SomeClass :
pass
>>> message = '''interpreter
... prompt'''
脚注
生成一个脚注.
目录
用 [TOC]来生成目录:
数学公式
使用MathJax渲染LaTex 数学公式,详见math.stackexchange.com .
行内公式,数学公式为:Γ ( n ) = ( n 1 ) ! n ∈ N Γ ( n ) = ( n 1 ) ! n ∈ N 。
块级公式:
x = b ± b 2 4 a c √ 2 a x = b ± b 2 4 a c 2 a
更多LaTex语法请参考 这儿 .
UML 图:
可以渲染序列图:
Created with Raphal 2.1.2 张三 张三 李四 李四 嘿,小四儿, 写博客了没? 李四愣了一下,说: 忙得吐血,哪有时间写。
或者流程图:
Created with Raphal 2.1.2 开始 我的操作 确认? 结束 yes no
关于 序列图 语法,参考 这儿 ,
关于 流程图 语法,参考 这儿 .
离线写博客
即使用户在没有网络的情况下,也可以通过本编辑器离线写博客(直接在曾经使用过的浏览器中输入write.blog.csdn.net/mdeditor 即可。Markdown编辑器 使用浏览器离线存储将内容保存在本地。
用户写博客的过程中,内容实时保存在浏览器缓存中,在用户关闭浏览器或者其它异常情况下,内容不会丢失。用户再次打开浏览器时,会显示上次用户正在编辑的没有发表的内容。
博客发表后,本地缓存将被删除。
用户可以选择 把正在写的博客保存到服务器草稿箱,即使换浏览器或者清除缓存,内容也不会丢失。
注意: 虽然浏览器存储大部分时候都比较可靠,但为了您的数据安全,在联网后,请务必及时发表或者保存到服务器草稿箱 。
浏览器兼容
目前,本编辑器对Chrome浏览器支持最为完整。建议大家使用较新版本的Chrome。
IE9以下不支持
IE9,10,11存在以下问题
不支持离线功能
IE9不支持文件导入导出
IE10不支持拖拽文件导入