begin 2023年04月15日16:49:35
本科软件工程专业有这么一门课叫《编译原理》,课程内容已经忘了七七八八,但尤为清楚的是上机大作业是拷贝的,课程分数92。
Given a language, define a representation for its grammar along with an interpreter that uses the representation to
interpret sentences in the language.
给定一个语言,定义其语法的表示以及一个用该表示来解释该语言中的句子的解释器。——《设计模式:可复用面向对象软件的基础》
解释器模式是一种行为型设计模式。
Use the Interpreter pattern when there is a language to interpret, and you can represent statements in the language as
abstract syntax trees.The Interpreter pattern works best when
the grammar is simple. For complex grammars, the class hierarchy for the grammar becomes large and unmanageable.
Tools such as parser generators are a better alternative in such cases. They can interpret expressions without
building abstract syntax trees, which can saves pace and possibly time.efficiency is not a critical concern. The most efficient interpreters are usually not implemented by interpreting
parse trees directly but by first translating them into another form. For example, regular expressions are often
transformed into state machines. But even then,the translator can be implemented by the Interpreter pattern, so the
pattern is still applicable.
当有语言要解释时,请使用解释器模式,您可以将语言中的语句表示为抽象语法树。解释器模式在以下情况下效果最佳:
解释器模式结构图:
抽象表达式(AbstractExpression):
终结符表达式(TerminalExpression):
非终结符表达式(NonterminalExpression):
上下文(Context):
客户端(Client):
实现一个简单函数绘图语言解释器,解释下面代码:
rot is 0;
origin is (0, 0);
scale is (2,20);
for T from 1 to 300 step 1 draw (t,-ln(t));
scale is (20,0.1);
for T from 0 to 8 step 0.1 draw (t,exp(t));
scale is (2,1);
for T from 0 to 300 step 1 draw (t,0);
for T from 0 to 300 step 1 draw (0,t);
for T from 0 to 120 step 1 draw (t,t);
scale is (2,0.1);
for T from 0 to 55 step 1 draw (t,-(t*t));
scale is (10,5);
for T from 0 to 60 step 1 draw (t,sqrt(t));
当然,我们的解释器还需要具备识别注释、出错处理等基本功能,下面是我实现过程中遵循的一些小的原则:
解释器模式常用于对简单语言的编译或分析实例中,为了掌握好它的结构与实现,必须先了解编译原理中的“文法、句子、语法树”等相关概念。
文法是用于描述语言的语法结构的形式规则。如:rot is 0;origin is (0, 0);scale is (2,20);
用文法表示:
<句子> -> <主语><谓语><表语>
<主语> -> <代词> | <名词>
<谓语> -> <动词>
<表语> -> <名词> | <形容词>
<名词> -> rot|origin|scale
<动词> -> is
<形容词> -> 0|(0,0)|(2,20)
注:这里的符号"->"表示“定义为”的意思,用"<"和">"括住的是非终结符,没有括住的是终结符。
句子是语言的基本单位,是语言集中的一个元素,它由终结符构成,能由“文法”推导出。
如,上面的文法可以推导出rot is 0;origin is (0, 0);scale is (2,20);
,所以这些都是句子。
语法树是句子结构的一种树型表示,它代表了句子的推导结果,它有利于理解句子语法结构的层次。
rot is 0;
的语法树如下:
本代码示例代码相对于本文来说过于冗长,下面带有有所省略,有兴趣请参考我的github:interpreter。
代码示例主要流程:
抽象表达式:
// 语法
public interface Grammar {
void interpret(Parser parser);
}
终结符表达式:
// 终结符类型
public enum TokenType {
ROT, IS, ORIGIN, SCALE, FOR, FROM, TO, STEP, DRAW, // 保留字
T, // 参数
SEMICOLON, COMMA, LEFT_BRACKET, RIGHT_BRACKET, // 分隔符
EOF, // 文件结束符
PLUS, MINUS, MUL, DIV, // 运算符
LN, EXP, SQRT, SIN, COS, POWER, // 函数
NUMBER // 数字
}
// 具体终结符
public class Token implements Grammar {
public static final Map<String, Token> TOKEN_MAP;
static {
Map<String, Token> tokenMap = new HashMap<>();
tokenMap.put("ROT", new Token(TokenType.ROT, "ROT"));
tokenMap.put("IS", new Token(TokenType.IS, "IS"));
tokenMap.put("ORIGIN", new Token(TokenType.ORIGIN, "ORIGIN"));
tokenMap.put("SCALE", new Token(TokenType.SCALE, "SCALE"));
tokenMap.put("FOR", new Token(TokenType.FOR, "FOR"));
tokenMap.put("FROM", new Token(TokenType.FROM, "FROM"));
tokenMap.put("TO", new Token(TokenType.TO, "TO"));
tokenMap.put("STEP", new Token(TokenType.STEP, "STEP"));
tokenMap.put("DRAW", new Token(TokenType.DRAW, "DRAW"));
tokenMap.put(";", new Token(TokenType.SEMICOLON, ";"));
tokenMap.put("(", new Token(TokenType.LEFT_BRACKET, "("));
tokenMap.put(")", new Token(TokenType.RIGHT_BRACKET, ")"));
tokenMap.put(",", new Token(TokenType.COMMA, ","));
tokenMap.put("NUMBER", new Token(TokenType.NUMBER, null));
tokenMap.put("EOF", new Token(TokenType.EOF, null));
tokenMap.put("T", new Token(TokenType.T, "T"));
tokenMap.put("+", new Token(TokenType.PLUS, "+"));
tokenMap.put("-", new Token(TokenType.MINUS, "-"));
tokenMap.put("*", new Token(TokenType.MUL, "*"));
tokenMap.put("/", new Token(TokenType.DIV, "/"));
tokenMap.put("LN", new Token(TokenType.LN, null));
tokenMap.put("EXP", new Token(TokenType.EXP, null));
tokenMap.put("SQRT", new Token(TokenType.SQRT, null));
tokenMap.put("SIN", new Token(TokenType.SIN, null));
tokenMap.put("COS", new Token(TokenType.COS, null));
tokenMap.put("^", new Token(TokenType.POWER, null));
TOKEN_MAP = tokenMap;
}
private TokenType type;
private Object value;
public Token(TokenType type, Object value) {
this.type = type;
this.value = value;
}
public TokenType getType() {
return type;
}
public Object getValue() {
return value;
}
public Token setValue(Object value) {
this.value = value;
return this;
}
@Override
public void interpret(Parser parser) {
// do nothing
}
}
非终结符表达式(部分代码省略):
// 非终结符
// 旋转语句
public class RotateStatement implements Grammar {
@Override
public void interpret(Parser parser) {
/**
* 解释ROT IS NUMBER,即旋转角度,将角度存入上下文中,供后续语句使用。
* 语法分析:先识别ROT,然后再识别IS,最后识别NUMBER。
**/
parser.matchToken(TokenType.ROT);
parser.matchToken(TokenType.IS);
parser.setRot((Double) parser.getCurrentToken().getValue());
parser.matchToken(TokenType.NUMBER);
parser.matchToken(TokenType.SEMICOLON);
}
}
上下文(部分代码已省略):
// 解释器
public class Parser {
// 语法规则
private Lexer lexer;
// 当前token
private Token currentToken;
// 输出
private String output;
// 旋转角度
private double rot;
// 原点坐标
private double originX;
private double originY;
// 缩放比例
private double scaleX;
private double scaleY;
private double from;
private double to;
private double step;
private ExprNode xNode;
private ExprNode yNode;
// 语句解释映射
private Map<TokenType, Grammar> statementMap;
public Parser(Lexer lexer) {
this.lexer = lexer;
this.output = "";
this.rot = 0;
this.originX = 0;
this.originY = 0;
this.scaleX = 1;
this.scaleY = 1;
statementMap = new HashMap<>();
statementMap.put(TokenType.ROT, new RotateStatement());
statementMap.put(TokenType.ORIGIN, new OriginStatement());
statementMap.put(TokenType.SCALE, new ScaleStatement());
statementMap.put(TokenType.FOR, new ForStatement());
}
}
//
客户端:
public class Client {
public static void main(String[] args) throws IOException {
Semantic semantic = new Semantic();
semantic.analyze();
}
}
解释器执行结果:
因为写画图代码的时间正值520,所以随手查找了心形坐标函数,执行结果如下,祝天下所有有情人终成眷属。
当你需要解释某种语言,无论这种语句是否通用,也许只有你自己能解释,并且该语言能表示为语法树,有不会太复杂,可以使用解释器模式。
函数绘图语言解释器
解释器模式
2023年05月21日17:32:23
由于博主水平有限,如果本文有什么错漏,请不吝赐教
感谢阅读,如果您觉得本文对你有帮助的话,可以点个推荐
大家好,又见面了,我是你们的朋友全栈君。1.开始学习时不要纠结DSP的具体结构,大体了解有哪些功能模块即可,DSP的工作原理不是重点,在后期使用时再详细弄懂所需结构的详情2.C2000系列即TMS320C2000包括F24XX,C28XX,F28XX为低端型号,C5000系列面向低功耗,C6000系列面向高性能3.TI的DSP型号含义例如:TMS320F2812PGFA例如:TMS320F2812PGFA1.前缀:TMX=实验器件;TMP=原型器件TMS=合格器件 2.系列号:320=TMS320系列 3.引导加载选项:(B) 4.工艺: C=COMS E=COMS;EPROM F=Flash;EEPROM LC=低电压CMOS(3.3V) LF=Flash;EPROM(3.3V) VC=低电压CMOS(3V) 5.器件类型: 20xDSP 24xDSP 54xDSP 55xDSP 62xDSP 64xDSP 67xDSP 3XDSP 6.封装类型: PAG=64-引脚塑料TQFP PGE=144-引脚塑料TQFP PZ=100-引脚塑料TQFP 7.温度范围:(默认0°C-70°C)
生信技能树核心成员,单细胞天地特约撰稿人,简书创作者,单细胞数据科学家。有过计算机视觉和影像组学数据分析经验的朋友,对感兴趣区域(regionofinterest,ROI)不会感到陌生。感兴趣区域就像它的字面意思一样直白,哪些区域您比较感兴趣?空间表达数据也允许我们在空间信息中找出这个ROI了。那么,在我们空间表达数据中的ROI是什么,有什么意义,如何确定?确定之后如何分析?这些有意思的议题,我们会在这篇文章中探讨。什么是ROI在机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域,ROI。在Halcon、OpenCV、Matlab等机器视觉软件上常用到各种算子(Operator)和函数来求得感兴趣区域ROI,并进行图像的下一步处理。这像我们在拿到分群或者富集结果之后说的【您感兴趣的亚群或你关注的通路】是一个意思,就是在一个切片上,哪个区域是您比较感兴趣的?没有无缘无故的兴趣,这个区域往往更接近我们的研究目的。而ROI的目的论本身,也反映了在选定之前它不是一个恒定的区域,如在第一阶段不是ROI的区域,下一阶段可能又是ROI了。所以
目录1、树状目录结构图2、/目录3、/etc/目录4、/usr/目录5、/var/目录6、/proc/目录7、/dev/目录下面红色字体为比较重要的目录1、树状目录结构图2、/目录目录描述/第一层次结构的根、整个文件系统层次结构的根目录。/bin/需要在单用户模式可用的必要命令(可执行文件);面向所有用户,例如:cat、ls、cp,和/usr/bin类似。/boot/引导程序文件,例如:kernel、initrd;时常是一个单独的分区[6]/dev/必要设备,例如:,/dev/null./etc/特定主机,系统范围内的配置文件。 关于这个名称目前有争议。在贝尔实验室关于UNIX实现文档的早期版本中,/etc被称为/etcetra目录,[7]这是由于过去此目录中存放所有不属于别处的所有东西(然而,FHS限制/etc存放静态配置文件,不能包含二进制文件)。[8]自从早期文档出版以来,目录名称已被以各种方式重新称呼。最近的解释包括反向缩略语如:"可编辑的文本配置"(英文"EditableTextConfiguration")或"扩展工
题目描述:AsequenceX_1,X_2,...,X_nisfibonacci-likeif:n>=3X_i+X_{i+1}=X_{i+2}foralli+2<=nGivenastrictlyincreasingarrayAofpositiveintegersformingasequence,findthelengthofthelongestfibonacci-likesubsequenceofA.Ifonedoesnotexist,return0.(RecallthatasubsequenceisderivedfromanothersequenceAbydeletinganynumberofelements(includingnone)fromA,withoutchangingtheorderoftheremainingelements.Forexample,[3,5,8]isasubsequenceof[3,4,5,6,7,8].)Example1:Input:[1,2,3,4,5,6,7,8] Output:5 Explanation: Thelongestsubs
交换器介绍 RabbitMQ中有三种主要的交互器分别如下交换器说明direct发布与订阅完全匹配topic主体,规则匹配fanout广播topic介绍 TopicExchange是比较复杂也比较灵活的种路由策略,在TopicExchange中,Queue通过routingkey绑定到TopicExchange上,当消息到达TopicExchange后,TopicExchange根据消息的routingkey消息路由到一个或者多Queue上,相比direct模式topic会更加的灵活些。 本案例通过两个项目来实现,一个consumer项目和一个provider项目。1.创建消费者项目结构配置文件spring.application.name=springcloud-mq spring.rabbitmq.host=192.168.88.150 spring.rabbitmq.port=5672 spring.rabbitmq.username=dpb spring.rabbitmq.password=123 #设置交换器的名称 mq.config.exchange=log.top
string storyboardName ="MyStoryBoard"; string myXamlElement ="MyXamlElement"; int newLeftPosition =120; Storyboard sb = XamlReader.Load(String.Format( @"<Storyboard xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"" x:Name=""{0}""> <DoubleAnimation Storyboard.TargetName=""{1}"" Storyboard.TargetProperty=""(Canvas.Left)""
之前有朋友做了一个可以直接对网页进行截图的小程序,询问我如何做小程序的推广,分享下我的一个思路,希望可以给读者一些借鉴。将一篇网站变成一张图片,通常我们在什么情况下用到这个工具呢?比如知乎、微信、新闻平台等内容网站的文章经常被删除,需要一个文章保存工具。比如微信上文章不方便直接保存到PC端,可以直接生成图片后自己建立索引。比如某些内容网站的文章跨平台转发格式会乱掉,而用图片就可以确保排版不会乱掉,是一个很好的体验。比如内容网站的一些文章不可以在离线状态下阅读,就可以通过这个提前保存文章到本地。场景其实需要在产品开发之前就想清楚,不过没想清楚也可以做了之后再来想,但记住一定要想,而且要不停的想。其实很多产品也都是边做边想,甚至做完继续深挖和扩散才发现核心场景的。想清楚后才能发现你的核心用户在哪,做精准推荐。场景想好后,可以开始考虑推广。任何一个产品的推广,其实都分为两步,基础推广与杠杆推广。小程序的基础推广可以参考下面的思路1.聚合平台PC时代,各大网页的聚合平台是搜索引擎和导航网站,他将各个网站聚合到了一起。移动互联网时代,APP的聚合平台有appstore和各大安卓应用商店,在这里你
什么是React高阶组件 React高阶组件就是以高阶函数的方式包裹需要修饰的React组件,并返回处理完成后的React组件。React高阶组件在React生态中使用的非常频繁,比如react-router中的withRouter以及react-redux中connect等许多API都是以这样的方式来实现的。 使用React高阶组件的好处 在工作中,我们经常会有很多功能相似,组件代码重复的页面需求,通常我们可以通过完全复制一遍代码的方式实现功能,但是这样页面的维护可维护性就会变得极差,需要对每一个页面里的相同组件去做更改。因此,我们可以将其中共同的部分,比如接受相同的查询操作结果、组件外同一的标签包裹等抽离出来,做一个单独的函数,并传入不同的业务组件作为子组件参数,而这个函数不会修改子组件,只是通过组合的方式将子组件包装在容器组件中,是一个无副作用的纯函数,从而我们能够在不改变这些组件逻辑的情况下将这部分代码解耦,提升代码可维护性。 自己动手实现一个高阶组件 前端项目里,带链接指向的面包屑导航十分常用,但由于面包屑导航需要手动维护一个所有目录路径与目录名映射的数组,而这里所有的数据
运行命令brewinstallnode,结果界面一直卡在UpdatingHomebrew...上,有两种解决办法 直接关闭brew每次执行命令时的自动更新(推荐) vim~/.bash_profile #新增一行 exportHOMEBREW_NO_AUTO_UPDATE=true复制 复制 支付宝打赏! 您的资助是我最大的动力!金额随意,欢迎来赏! 微信打赏! 您的资助是我最大的动力!金额随意,欢迎来赏! 如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】按钮。 如果,您希望更容易地发现我的新博客,不妨点击一下绿色通道的【关注我】。 如果,想给予我更多的鼓励,求打 因为,我的写作热情也离不开您的肯定与支持,感谢您的阅读,我是【Blue·Sky】! 【China-测试开发】技术交流群期待你的加入【193056556】 【欢迎扫码关注:日益】微信订阅号【riyi18】
java的编译时错误和运行时错误 java中的super http://c.biancheng.net/view/6394.html java中的集合与map java数组和集合 Java中HashMap的实现原理 java中的clone 详解Java中的clone方法 java的修饰符 https://www.runoob.com/java/java-modifier-types.html private修饰的方法仅限于同一个类访问,且不能被继承 接口里的变量都隐式声明为publicstaticfinal,而接口里的方法默认情况下访问权限为public。 接口的default方法 https://www.liaoxuefeng.com/wiki/1252599548343744/1260456790454816 可被覆写 静态方法只能访问静态字段 Java对象类型转换和强制对象类型转换 Java对象类型转换和强制对象类型转换 实例方法与引用变量实际引用的对象的方法进行绑定,这种绑定属于动态绑定,因为是在运行时由Java虚拟机动态决定的。例如,anim
前言: 早期jenkins承担了kubernetes中的ci/cd全部功能JenkinsPipeline演进,这里准备将cd持续集成拆分出来到spinnaker! 当然了正常的思路应该是将jenkinsspinnaker的用户账号先打通集成ldap.spinnaker账号系统已经集成ldap.jenkins之前也做过相关的试验。这里关于jenkins集成ldap的步骤就先省略了。毕竟目标是拆分pipeline流水线实践。账号系统互通还没有那么有紧迫性!。当然了第一步我觉得还是少了镜像的扫描的步骤,先搞一波镜像的扫描!毕竟安全才是首位的 关于jenkins流水线pipeline的镜像扫描 注:image镜像仓库使用了harbor Trivy harbor默认的镜像扫描器是Trivy。早的时候貌似是clair?记得 查看harbor的api(不能与流水线集成提供扫描报告) 看了一眼harbor的api。harbor的api可以直接scan进行扫描: 但是这里有个缺陷:我想出报告直接展示在jenkins流水线中啊,GET也只能获取log,我总不能jenkins流水线集成了harbo
H3C的链路聚合配置方式和cisco华为都有些不同, 来一起看一下吧 如图所示, G1/0/1和G1/0/2接口配置链路聚合 [sw1]vlan10 [sw1]vlan20 [sw1]interBridge-Aggregation1 [sw1-Bridge-Aggregation1]portlink-typetrunk [sw1]interrangeg1/0/1tog1/0/2 [sw1-if-range]portlink-aggregationgroup1 [sw1-if-range]portlink-typetrunk [sw1-if-range]porttrunkpervlan1020 [sw1]interBridge-Aggregation1 [sw1-Bridge-Aggregation1]portlink-typetrunk [sw1-Bridge-Aggregation1]porttrunkpervlan1020 SW2做同样的配置即可 查看配置 Dislink-aggre
特征 CVS Git Mercurial Subversion 是否原子提交 CVS:没有.CVS提交不是原子的 Git:是的.提交都是原子的 Mercurial:是的 Subversion:提交都是原子的 文件和目录是否可以移动或重命名 CVS:不是.重命名不支持.如果手动进行,可能会损坏历史记录 Git:支持重命名,这是很实用的目的.git甚至能检测到重命名之后文件的改变.尽管如此,基于特殊的存储结构,重命名不会被显示的记录,git能够推导出来(在实际使用中很容易做到) Mercurial:是的,重命名是支持的 Subversion:是的.支持重命名 在移动或重命名之后智能合并 CVS:不能.重命名都不支持,就不必说智能了 Git:不支持.细节在GitFAQ里:“Git有一个重命名的命令gitmv,但是这仅仅是为了便利.效果和移掉某个文件,增加另外一个文件没有任何区别” Mercurial:是的.重命名之后智能合并是支持的.Mercurtial文档说:“如果我修改一个文件,而你重新命名了这个文件,然后我们合并我们的变更,那么我所做的修改就会被更新到根据旧文件名字而
11.长度限制 2<script> 3functiontest() 4{ 5if(document.a.b.value.length>50) 6{ 7alert("不能超过50个字符!"); 8document.a.b.focus(); 9returnfalse; 10} 11} 12</script> 13<formname=aonsubmit="returntest()"> 14<textareaname="b"cols="40"wrap="VIRTUAL"rows="6"></textarea> 15<inputtype="submit"name="Submit"value="check"> 16</form> 17 182.只能是汉字 19<inputonkeyup="value="/oblog/value.replace(/[^\u4E00-\u9FA5]/g,'')"> 20 213."只能是英文 22<scriptlanguage=javascript> 23
一、NLP概念 1.1文本消歧:多模态、上下文信息 1.2应用:问答系统 情感分析(产品评论、事件监测、舆情监控、股票价格预测) 15年之前vs15年之后: 机器翻译(很多好的模型都从机器翻译中来) 自动摘要 信息抽取(成熟)-->自动问答系统中的一个子模块 对话系统-->集大成者。 用简单的心理学trick去解决未知 推荐系统 1.3技术栈: 二、NLP的过程: 2.1分词 Tool: Jieba分词https://github.com/fxsjy/jieba SnowNLPhttps://github.com/isnowfy/snownlp 清华LTPhttp://www.ltp-cloud.com/ HanNLPhttps://github.com/hankcs/HanLP 算法: 1.前向最大匹配、后向最大匹配(中文后向更优) 2.基于语言模型(计算句子概率的模型)去分词,判断一句话是不是人话 N-Gram(用马尔可夫假设)-->Smoothing 2.2拼写纠正(英文为主) 2.3停用词过滤 Zipfislaw规律 2.4词的标准化 3.文本表
客户现场反馈,top的检查结果中,一个CPU的占用一直是100%。实际上现场有4个CPU,而且这个服务器是mysql专属服务器。 我的第一反应是io_thread一类的参数设置有问题,检查以后发现read和write的thread设置都是4,这和CPU数一致,因此可以断定这并不是单颗CPU占用过高的问题。 接下来需要确认MySQL究竟有没有利用到多核CPU,这个时候需要的工具叫做pidstat,命令如下: pidstat-u-t-p18158 得到的结果如下图所示: 复制 可以看出其实mysqld是可以利用到多核CPU的,那么此时可以得到一个推断: 某个CPU上做的事情太占资源了 一般这种最占资源的工作一定会在INNODB_TRX里留下一些端倪,因此检查一下: 复制 反复的检查TRX,发现mysql在不停的执行这个SQL,只是where条件里的值发生了变化,至此我可以推断出业务应该是写了一个循环来遍历一个list,然后对每个item都执行update操作。 应该是写了这么一段代码在处理问题: for(iteminlist){ update_db(item); }
效果 设计思路 需求分析 图片浏览,上/下一张,放大缩小等基本功能。可以继续拓展的功能:缩略图、旋转,画笔修改等。此外,缩放实现较为简单,所以会出现失真。设计此类软件功能可参考ACDSee或irfanview等看图软件。 知识点 1.文件过滤、文件IO:FileFilter 2.文件对话框:JFileChooser(添加文件过滤功能) 3.浏览器主界面:JToolBar/JMenuBar/JScrollPane 4.响应事件:ActionListener/AbstractAction 5.展示图片:ImageIcon 设计模式 1.单例:业务处理类并不是无状态的Java对象,而是保存着浏览目录、缩放比例等信息。 具体代码: publicstaticViewerServicegetInstance(){ if(null==service){ service=newViewerService(); } returnservice; }复制 2.反射:通过反射创建实例,避免if...elseif.....else...,增强程
packagecom.linkwee.web.service; importjava.util.List; importcom.linkwee.api.request.cim.ProductPageListClassifyRequest; importcom.linkwee.api.request.cim.ProductPageListRecommendRequest; importcom.linkwee.api.request.cim.ProductPageListRequest; importcom.linkwee.api.request.cim.ScreenProductPageListRequest; importcom.linkwee.api.response.cim.ProductPageListResponse; importcom.linkwee.core.orm.paging.Page; publicinterfaceElasticsearchProductService{ /** *查询产品列表 *@paramproductPageListRequest *