日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 3.0参考之SpEL

發布時間:2024/4/17 javascript 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 3.0参考之SpEL 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://sishuok.com/forum/blogPost/list/2463.html

?http://docs.spring.io/spring/docs/3.0.x/reference/expressions.html

http://cnicwsh.iteye.com/blog/504937

Spring 3.0 RC1發布,一些新特性很吸引人,看了一下Reference,順便翻譯了SpEL這節,水平有限,還望指教。

Spring 3.0 Reference:http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/index.html?

?

排版過的見:http://blog.csdn.net/wsh622827/archive/2009/10/27/4733524.aspx

?

Part III 核心技術

6.Spring 表達式語言(SpEL)

?

  • 6.1 簡介
  • 6.2 特性概覽
  • 6.3 使用Spring Expression接口進行表達式求值
  • 6.4 bean定義的表達式支持
  • 6.5 語言參考
  • 6.6 示例類

6.1 簡介

??? Spring表達式語言(簡稱SpEL)是一個支持運行時查詢和操作對象圖的強大的表達式語言。其語法類似于統一EL,但提供了額外特性,顯式方法調用和基本字符串模板函數。

??? 同很多可用的Java 表達式語言相比,例如OGNL,MVEL和JBoss EL,SpEL的誕生是為了給Spring社區提供一個可以給Spring目錄中所有產品提供單一良好支持的表達式語言。其語言特性由Spring目錄中的項目需求驅動,包括基于eclipse的SpringSource套件中的代碼補全工具需求。那就是說,SpEL是一個基于技術中立的API允許需要時與其他表達式語言集成。

??? SpEL作為Spring目錄中表達式求值的基礎,它并不是直接依賴于Spring而是可以被獨立使用。為了能夠自包含,本章中的許多示例把SpEL作為一個獨立的表達式語言來使用。這就需要創建一些如解析器的引導基礎組件類。大多數Spring用戶只需要為求值編寫表達式字符串而不需要關心這些基礎組件。一個典型的使用例子是集成SpEL和創建基于XML或注解的bean定義,見6.4 bean定義的表達式支持一節。

??? 本章涵蓋了表達式語言的特性,API和語法。在很多地方,一個Inventor類和Invertor的Society類作為表達式求值的目標對象。這些類聲明和操作它們使用的數據列在本章的末尾。

6.2 特性概覽

??? 表達式語言支持下列功能:

??? 字符表達式

??? 布爾和關系操作符

??? 正則表達式

??? 類表達式

??? 訪問properties,arrays,lists,maps

??? 方法調用

??? 關系操作符

??? 賦值

??? 調用構造器

??? 三元操作符

??? 變量

??? 用戶自定義函數

??? 集合投影

??? 集合選擇

??? 模板表達式

6.3 使用Spring Expression接口進行表達式求值

??? 這一節介紹SpEL接口和其表達式語言的簡單實用。完整的語言參考參見語言參考一節。

??? 下面的代碼使用SpEL API求字符表達式‘Hello World’的值。

??? ExpressionParserparser= new SpelExpressionParser();

Expressionexp=parser.parseExpression("'HelloWorld'");

Stringmessage=(String)exp.getValue();

??? message變量的值是最簡單的‘Hello World’。

??? 最常使用的SpEL類和接口在包org.springframework.expression和其子包以及spel.support中。

??? ExpressionParser接口用來解析一個表達式字符串。在這個例子中,表達式串是一個被單引號包括標注的字符串。Expression接口用來求前面定義的表達式串的值。當調用parser.parseExpression和exp.getValue時分別可能拋出ParseException和EvaluationException異常。

??? SpEL支持一系列特性,例如方法調用,訪問屬性和調用構造器。

??? 下面調用字符串文字的concat方法作為方法調用的一個例子。

??? ExpressionParserparser= new SpelExpressionParser();

Expressionexp=parser.parseExpression("'HelloWorld'.concat('!')");

Stringmessage=(String)exp.getValue();

message的值為‘Hello World!’。

下面的String屬性Bytes可以被調用作為調用JavaBean屬性的一個例子。

ExpressionParserparser= new SpelExpressionParser();

//invokes'getBytes()'

Expressionexp=parser.parseExpression("'HelloWorld'.bytes");

byte[]bytes=(byte[])exp.getValue();

SpEL使用標準的‘.’符號支持屬性嵌套和屬性設值,例如:prop1.prop2.prop3.

公共屬性也可以被訪問。

ExpressionParserparser= new SpelExpressionParser();

//invokes'getBytes().length'

Expressionexp=parser.parseExpression("'HelloWorld'.bytes.length");

int length=(Integer)exp.getValue();

使用字符串構造器而不是字符串文字。

ExpressionParserparser= new SpelExpressionParser();

Expressionexp=parser.parseExpression("newString('helloworld').toUpperCase()");

Stringmessage=exp.getValue(String.class);

記住使用泛型方法public <T> T getValue(Class<T> desiredResultType)。使用這個方法省去了需要時對表達式的值顯式類型轉換。如果該值不能被轉換為T或者使用已注冊的類型轉換器轉換則會拋出EvaluationException.

SpEL中更常見的用途是提供一個針對特定對象實例求值的表達式字符串。在下面的例子中,我們檢索一個Inventor類的實例的name屬性。

//Createandsetacalendar

GregorianCalendarc= new GregorianCalendar();

c.set(1856,7,9);

//Theconstructorargumentsarename,birthday,andnationality.

Inventortesla= new Inventor("NikolaTesla",c.getTime(), "Serbian");

ExpressionParserparser= new SpelExpressionParser();

Expressionexp=parser.parseExpression("name");

EvaluationContextcontext= new StandardEvaluationContext();

context.setRootObject(tesla);

Stringname=(String)exp.getValue(context);

在最后一行,該字符串變量'name'將被設置為“Nikola Tesla”。類StandardEvaluationContext是您可以指定對象的將被求值的“name”屬性。你可以重復使用相同的表達式,在求值上下文內設定一個新的根對象。表達式是使用反射求值。

Note:在單獨使用SpEL時,你需要創建一個解析器并提供一個求值上下文。但是更為廣泛的應用僅僅提供一個SpEL表達式字符串作為配置文件的一部分。例如為Spring bean或Spring Web Flow定義。這種情況下,解析器,求值上下文,根對象和其他預定義變量都會被隱含創建。

作為最后一個例子,使用前面例子中的Inventor對象中使用布爾操作符。

Expressionexp=parser.parseExpression("name=='NikolaTesla'");

boolean result=exp.getValue(context,Boolean.class); //evaluatestotrue

EvaluationContext接口

??? EvaluationContext接口用來求一個解析屬性,方法,域的表達式值以及幫助類型轉換。其即插即用實現StandardEvaluationContext使用反射機制來操作對象。為獲得好的性能緩存java.lang.reflect的Method,Field,和Constructor實例。

??? 該StandardEvaluationContext是你用來通過方法setRootObject指定求值根對象或傳遞根對象到構造器的接口。你還可以指定將在表達式中使用的方法setVariable和registerFunction的變量和函數。變量和函數使用的描述見語言參考部分的變量和函數。StandardEvaluationContext還是你可以注冊自定義ConstructorResolvers,MethodResolvers,和PropertyAccessors來擴展SpEL如何計算表達式。請參閱這些類的JavaDoc了解詳情

類型轉換

??? 默認情況下,SpEL使用的轉換服務可在Spring的核心(org.springframework.core.convert.ConversionService)找到。這種轉換的服務由很多內建的為通常轉換的轉換器構成,但也是可擴展的,這樣可以添加自定義類型之間的轉換。此外它的主要支持是它是泛型敏感的。這意味著,當處理表達式中的泛型時,SpEL將嘗試轉換來維持對所遇到的任何對象類型的正確性。?

這是什么在實踐中意味著什么呢?比如賦值,用setValue()來設置List類型,實際是List<Boolean>。SpEL將會認識到,在List的元素需要在使用之前轉換為布爾類型。一個簡單的例子:

class Simple{

public List<Boolean>booleanList= new ArrayList<Boolean>();

}

Simplesimple= new Simple();

simple.booleanList.add(true);

StandardEvaluationContextsimpleContext= new StandardEvaluationContext(simple);

//falseispassedinhereasastring.SpELandtheconversionservicewill

//correctlyrecognizethatitneedstobeaBooleanandconvertit

parser.parseExpression("booleanList[0]").setValue(simpleContext, "false");

//bwillbefalse

Booleanb=simple.booleanList.get(0);

6.4 bean定義的表達式支持

??? SpEL可以和Bean定義中基于XML或注解的元數據配置一起使用。兩種情況下的語法都是如#{ <expression string> }的形式。

基于XML的配置

??? 下面一個屬性或者構造參數值可以使用表達式設值。

??? <bean id="numberGuess" class="org.spring.samples.NumberGuess">

<property name="randomNumber" value="#{T(java.lang.Math).random()*100.0}"/>

<!--otherproperties-->

</bean>

??? 變量‘systemProperties’是預先定義的,所以你可以在表達式中如下使用,記住在這個上下文中你不必在預定義的變量前加#號。

??? <bean id="taxCalculator" class="org.spring.samples.TaxCalculator">

<property name="defaultLocale" value="#{systemProperties['user.region']}"/>

<!--otherproperties-->

</bean>

你可以通過名字引用其他bean的屬性,如下:

<bean id="numberGuess" class="org.spring.samples.NumberGuess">

<property name="randomNumber" value="#{T(java.lang.Math).random()*100.0}"/>

<!--otherproperties-->

</bean>

<bean id="shapeGuess" class="org.spring.samples.ShapeGuess">

<property name="initialShapeSeed" value="#{numberGuess.randomNumber}"/>

<!--otherproperties-->

</bean>

基于注解的配置

??? @Value注解可以在域,方法和方法/構造器參數中使用來指定一個默認值。

??? 這是一個設置域變量默認值的例子。

publicstaticclass FieldValueTestBean

@Value("#{systemProperties['user.region']}")

private StringdefaultLocale;

publicvoid setDefaultLocale(StringdefaultLocale)

{

this.defaultLocale=defaultLocale;

}

public StringgetDefaultLocale()

{

returnthis.defaultLocale;

}

}

和下面在屬性的setter方法中使用等價。

publicstaticclass PropertyValueTestBean

private StringdefaultLocale;

@Value("#{systemProperties['user.region']}")

publicvoid setDefaultLocale(StringdefaultLocale)

{

this.defaultLocale=defaultLocale;

}

public StringgetDefaultLocale()

{

returnthis.defaultLocale;

}

}

??? 自動裝配的方法和構造器同樣可以使用@Value注解。

publicclass SimpleMovieLister{

private MovieFindermovieFinder;

private StringdefaultLocale;

@Autowired

publicvoid configure(MovieFindermovieFinder,

@Value("#{systemProperties['user.region']}"}StringdefaultLocale){

this.movieFinder=movieFinder;

this.defaultLocale=defaultLocale;

}

//...

}

?

publicclass MovieRecommender{

private StringdefaultLocale;

private CustomerPreferenceDaocustomerPreferenceDao;

@Autowired

public MovieRecommender(CustomerPreferenceDaocustomerPreferenceDao,

@Value("#{systemProperties['user.country']}"}StringdefaultLocale){

this.customerPreferenceDao=customerPreferenceDao;

this.defaultLocale=defaultLocale;

}

//...

}

6.5 語言參考

文字表達式

??? 支持的文字表達的類型是字符串,日期,數值(整型,實型,和十六進制),布爾和空。字符串是由單引號分隔。使用反斜杠字符轉移把一個單引號字符本身放在字符串中。以下清單顯示文字的簡單用法。通常它們不會使用這樣單獨使用,而是作為一個更復雜的表達式的一部分,例如,使用一個文字表達式作為邏輯比較運算符的一邊。

ExpressionParserparser= new SpelExpressionParser();

//evalsto"HelloWorld"

StringhelloWorld=(String)parser.parseExpression("'HelloWorld'").getValue();

double avogadrosNumber=(Double)parser.parseExpression("6.0221415E+23").getValue();

//evalsto2147483647

int maxValue=(Integer)parser.parseExpression("0x7FFFFFFF").getValue();

boolean trueValue=(Boolean)parser.parseExpression("true").getValue();

ObjectnullValue=parser.parseExpression("null").getValue();

??? 數字支持負號,指數符號的使用和小數點。默認情況下實數解析使用Double.parseDouble()。

Properties,Arrays,Lists,Maps,Indexers

??? 用屬性引用導航很簡單,只需使用一個句點來表示一個嵌套的屬性值。Inventor類實例,pupin和tesla,使用示例中使用的類一節中列出的數據填充。要“向下”導航并獲得tesla的出生年份和pupin的出生的城市則使用下列表達式。

//evalsto1856

int year=(Integer)parser.parseExpression("Birthdate.Year+1900").getValue(context);

Stringcity=(String)parser.parseExpression("placeOfBirth.City").getValue(context);

??? 屬性名的首字母區分大小寫,數組和列表的內容使用方括號符號得到。

ExpressionParserparser= new SpelExpressionParser();

//InventionsArray

StandardEvaluationContextteslaContext= new StandardEvaluationContext(tesla);

//evaluatesto"Inductionmotor"

Stringinvention=parser.parseExpression("inventions[3]").getValue(teslaContext,

String.class);

//MembersList

StandardEvaluationContextsocietyContext= new StandardEvaluationContext(ieee);

//evaluatesto"NikolaTesla"

Stringname=parser.parseExpression("Members[0].Name").getValue(societyContext,String.class);

//ListandArraynavigation

//evaluatesto"Wirelesscommunication"

Stringinvention=parser.parseExpression("Members[0].Inventions[6]").getValue(societyContext,

String.class);

Map的內容通過指定括號內的文字鍵值得到。在這種情況下,因為Officers Map的鍵是字符串,我們可以指定字符串。

//Officer'sDictionary

Inventorpupin=parser.parseExpression("Officers['president']").getValue(societyContext,

Inventor.class);

//evaluatesto"Idvor"

Stringcity=

parser.parseExpression("Officers['president'].PlaceOfBirth.City").getValue(societyContext,

String.class);

//settingvalues

parser.parseExpression("Officers['advisors'][0].PlaceOfBirth.Country").setValue(societyContext,

"Croatia");

方法

方法調用采用典型的Java編程語法。您還可以調用文字的方法。可變參數也支持。

//stringliteral,evaluatesto"bc"

Stringc=parser.parseExpression("'abc'.substring(2,3)").getValue(String.class);

//evaluatestotrue

boolean isMember=parser.parseExpression("isMember('MihajloPupin')").getValue(societyContext,

Boolean.class);

操作符

??? 關系操作符

??? 使用標準的操作符號支持關系操作符:等于,不等于,小于,小于等于,大于,大于等于。

//evaluatestotrue

boolean trueValue=parser.parseExpression("2==2").getValue(Boolean.class);

//evaluatestofalse

boolean falseValue=parser.parseExpression("2<-5.0").getValue(Boolean.class);

//evaluatestotrue

boolean trueValue=parser.parseExpression("'black'<'block'").getValue(Boolean.class);

??? 除此之外,SpEL支持‘instanceof’和基于正則表達式的‘match’操作。

//evaluatestofalse

boolean falseValue=parser.parseExpression("'xyz'instanceofT(int)").getValue(Boolean.class);

//evaluatestotrue

boolean trueValue=

parser.parseExpression("'5.00'matches'^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

//evaluatestofalse

boolean falseValue=

parser.parseExpression("'5.0067'matches'^-?\\d+(\\.\\d{2})?$'").getValue(Boolean.class);

??? 邏輯操作符

??? 支持的邏輯操作符包括and,or和not,使用方法如下。

//--AND--

//evaluatestofalse

boolean falseValue=parser.parseExpression("trueandfalse").getValue(Boolean.class);

//evaluatestotrue

Stringexpression= "isMember('NikolaTesla')andisMember('MihajloPupin')";

boolean trueValue=parser.parseExpression(expression).getValue(societyContext,Boolean.class);

//--OR--

//evaluatestotrue

boolean trueValue=parser.parseExpression("trueorfalse").getValue(Boolean.class);

//evaluatestotrue

Stringexpression= "isMember('NikolaTesla')orisMember('AlbertEinstien')";

boolean trueValue=parser.parseExpression(expression).getValue(societyContext,Boolean.class);

//--NOT--

//evaluatestofalse

boolean falseValue=parser.parseExpression("!true").getValue(Boolean.class);

//--ANDandNOT--

Stringexpression= "isMember('NikolaTesla')and!isMember('MihajloPupin')";

boolean falseValue=parser.parseExpression(expression).getValue(societyContext,Boolean.class);

算術操作符

加法運算符可以用于數字,字符串和日期。減法可用于數字和日期。乘法和除法僅可以用于。其他支持的數學運算包括取模(%)和指數冪(^)。使用標準的運算符優先級。這些運算符示例如下。

//Addition

int two=parser.parseExpression("1+1").getValue(Integer.class); //2

StringtestString=

parser.parseExpression("'test'+''+'string'").getValue(String.class); //'teststring'

//Subtraction

int four=parser.parseExpression("1--3").getValue(Integer.class); //4

double d=parser.parseExpression("1000.00-1e4").getValue(Double.class); //-9000

//Multiplication

int six=parser.parseExpression("-2*-3").getValue(Integer.class); //6

double twentyFour=parser.parseExpression("2.0*3e0*4").getValue(Double.class); //24.0

//Division

int minusTwo=parser.parseExpression("6/-3").getValue(Integer.class); //-2

double one=parser.parseExpression("8.0/4e0/2").getValue(Double.class); //1.0

//Modulus

int three=parser.parseExpression("7%4").getValue(Integer.class); //3

int one=parser.parseExpression("8/5%2").getValue(Integer.class); //1

//Operatorprecedence

int minusTwentyOne=parser.parseExpression("1+2-3*8").getValue(Integer.class); //-21

賦值

??? 屬性設置是通過使用賦值運算符。這通常是在調用setValue中執行但也可以在調用getValue內。

Inventorinventor= new Inventor();

StandardEvaluationContextinventorContext= new StandardEvaluationContext(inventor);

parser.parseExpression("Name").setValue(inventorContext, "AlexanderSeovic2");

//alternatively

Stringaleks=parser.parseExpression("Name='AlexandarSeovic'").getValue(inventorContext,

String.class);

類型

特殊的‘T'操作符可以用來指定一個java.lang.Class的實例('類型')。靜態方法調用也使用此操作符。該StandardEvaluationContext使用TypeLocator尋找類型,StandardTypeLocator(可更換)建立在java.lang包的基礎上。這意味著T()引用在java.lang中的類型不須被完全限定,但所有其他類型的引用必須。

ClassdateClass=parser.parseExpression("T(java.util.Date)").getValue(Class.class);

ClassstringClass=parser.parseExpression("T(String)").getValue(Class.class);

boolean trueValue=

parser.parseExpression("T(java.math.RoundingMode).CEILING<T(java.math.RoundingMode).FLOOR")

.getValue(Boolean.class);

構造器

可以使用new運算符調用構造器。完全限定類名應被用于所有類型除了原始類型和字符串(如整型,浮點,等等,可以使用)。

Inventoreinstein=

p.parseExpression("neworg.spring.samples.spel.inventor.Inventor('AlbertEinstein',

'German')")

.getValue(Inventor.class);

//createnewinventorinstancewithinaddmethodofList

p.parseExpression("Members.add(neworg.spring.samples.spel.inventor.Inventor('AlbertEinstein',

'German'))")

.getValue(societyContext);

變量

變量可以在表達式中使用語法#’變量名’引用。變量設置使用StandardEvaluationContext的方法setVariable。

Inventortesla= new Inventor("NikolaTesla", "Serbian");

StandardEvaluationContextcontext= new StandardEvaluationContext(tesla);

context.setVariable("newName", "MikeTesla");

parser.parseExpression("Name=#newName").getValue(context);

System.out.println(tesla.getName()) //"MikeTesla"

??? #this變量

??? #this變量通常被定義和引用當前求值對象(該對象的不合格引用將解決)。

//createanarrayofintegers

List<Integer>primes= new ArrayList<Integer>();

primes.addAll(Arrays.asList(2,3,5,7,11,13,17));

//createparserandsetvariable'primes'asthearrayofintegers

ExpressionParserparser= new SpelExpressionParser();

StandardEvaluationContextcontext= new StandardEvaluationContext();

context.setVariable("primes",primes);

//allprimenumbers>10fromthelist(usingselection?{...})

//evaluatesto[11,13,17]

List<Integer>primesGreaterThanTen=

(List<Integer>)parser.parseExpression("#primes.?[#this>10]").getValue(context);

函數

??? 你可以通過注冊可在表達式字符串內調用的用戶自定義函數來擴展SpEL。使用StandardEvaluationContext中的下列方法注冊函數。

publicvoid registerFunction(Stringname,Methodm)

??? 所引用的Java方法實現該函數,例如如下這個有用的反轉字符串方法。

publicabstractclassStringUtils{

publicstaticStringreverseString(Stringinput){

StringBuilderbackwards=newStringBuilder();

for(inti=0;i<input.length();i++)

backwards.append(input.charAt(input.length()-1-i));

}

returnbackwards.toString();

}

}

??? 隨后這個方法就可以在求值上下文注冊并在表達式字符串中使用了。

ExpressionParserparser= new SpelExpressionParser();

StandardEvaluationContextcontext= new StandardEvaluationContext();

context.registerFunction("reverseString",

StringUtils.class.getDeclaredMethod("reverseString",

new Class[]{String.class }));

StringhelloWorldReversed=

parser.parseExpression("#reverseString('hello')").getValue(context,String.class);

三元操作符(If-Then-Else)

??? 可以在表達式內使用if-then-else條件邏輯三元操作符。下面是個小例子:

StringfalseString=

parser.parseExpression("false?'trueExp':'falseExp'").getValue(String.class);

??? 這個情況下,布爾false結果返回‘falseExp‘字符串,一個真實的例子如下:

parser.parseExpression("Name").setValue(societyContext, "IEEE");

societyContext.setVariable("queryName", "NikolaTesla");

expression= "isMember(#queryName)?#queryName+'isamemberofthe'" +

"+Name+'Society':#queryName+'isnotamemberofthe'+Name+'Society'"

StringqueryResultString=

parser.parseExpression(expression).getValue(societyContext,String.class);

//queryResultString="NikolaTeslaisamemberoftheIEEESociety"

??? 下一節將看到三元操作符更短的語法Elvis操作符。

Elvis操作符

??? ElvIs操作符是Groovy語言中使用的三元操作符的縮短。在三元運算符中通常要重復變量兩次,例如:

Stringname="ElvisPresley";

StringdisplayName=name!=null?name:"Unknown";

可以使用Elvis操作符替代,命名為和Elvis相似的風格。

ExpressionParserparser= new SpelExpressionParser();

Stringname=parser.parseExpression("null?:'Unknown'").getValue(String.class);

System.out.println(name); //'Unknown'

這里是一個復雜的例子。

ExpressionParserparser= new SpelExpressionParser();

Inventortesla= new Inventor("NikolaTesla", "Serbian");

StandardEvaluationContextcontext= new StandardEvaluationContext(tesla);

Stringname=parser.parseExpression("Name?:'ElvisPresley'").getValue(context,String.class);

System.out.println(name); //MikeTesla

tesla.setName(null);

name=parser.parseExpression("Name?:'ElvisPresley'").getValue(context,String.class);

System.out.println(name); //ElvisPresley

安全導航操作符

?? ?安全導航操作符來源于Groovy語言,它避免了空指針異常。通常當你有一個對象的引用,在訪問其方法或屬性時你需要驗證該引用是否為空。為了避免這種情況,安全導航操作符,只會返回null而不是拋出異常。

ExpressionParserparser= new SpelExpressionParser();

Inventortesla= new Inventor("NikolaTesla", "Serbian");

tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan"));

StandardEvaluationContextcontext= new StandardEvaluationContext(tesla);

Stringcity=parser.parseExpression("PlaceOfBirth?.City").getValue(context,String.class);

System.out.println(city); //Smiljan

tesla.setPlaceOfBirth(null);

city=parser.parseExpression("PlaceOfBirth?.City").getValue(context,String.class);

System.out.println(city); //null-doesnotthrowNullPointerException!!!

集合選擇

??? 選擇是一個強大的表達式語言特性,它允許你通過從入口選擇將原集合轉換為其他集合。

選擇使用語法?[selectExpression]。這將過濾原集合并返回包含原集合子集的新的集合。例如,選擇將允許我們很容易得到Serbian 發明者列表。

List<Inventor>list=(List<Inventor>)

parser.parseExpression("Members.?[Nationality=='Serbian']").getValue(societyContext);

??? 通常是對List和Map的選擇。在前一種情況下的選擇標準是針對每個人的列表求值而對Map選擇標準是針對每一個映射項(Java類型Map.Entry對象)求值,而評價。Map入口有其如屬性的可訪問的鍵和值供選擇使用。?

這個表達式將返回一個新的Map,其元素由原始Map中項的值小于27的元素組成。

MapnewMap=parser.parseExpression("map.?[value<27]").getValue();

??? 除了返回所有被選擇的元素,也可以檢索第一個和最后一個值。用^[…]獲得第一個匹配入口,用$[…]獲得最后一個匹配入口。

集合投影

投影允許集合驅動子表達式的求值,其結果是一個新的集合。對于投影語法![projectionExpression]。最容易理解的例子,假設我們有一個發明者列表,但要在城市名單中尋找他們在那里出生。我們要對發明者列表中每項有效地求出‘placeOfBirth.city'。使用投影:

//returns['Smiljan','Idvor']

ListplacesOfBirth=(List)parser.parseExpression("Members.![placeOfBirth.city]");

??? Map也可以用于驅動投影,這時投影表達式對Map中的每個項目求值(作為一個Java Map.Entry表示)。跨越Map投影的結果是對每個Map入口投影表達式求值后組成的列表。

表達式模板

??? 表達式模板允許與一個或多個求值塊復合文字文本。每個求值塊有可自定義的前綴和后綴的字符定界,一個普遍的選擇是使用的分隔符$()定界。例如,

StringrandomPhrase=

parser.parseExpression("randomnumberis${T(java.lang.Math).random()}",

new TemplatedParserContext()).getValue(String.class);

//evaluatesto"randomnumberis0.7038186818312008"

??? 該字符串的求值是通過連接文字文本的‘random number is’和$()定界符內求值表達式的結果,在這里是調用的random()方法的結果。parseExpression()方法的第二個參數是ParserContext的類型。該ParserContext接口通常影響表達式如何被解析以支持模板功能。在TemplatedParserContext的定義如下所示。

publicclass TemplatedParserContext implements ParserContext{

public StringgetExpressionPrefix(){

return "${";

}

public StringgetExpressionSuffix(){

?

return "}";

}

publicboolean isTemplate(){

return true;

}

}

6.6 示例中使用的類

?

================

5.3? SpEL語法

5.3.1? 基本表達式

一、字面量表達式: SpEL支持的字面量包括:字符串、數字類型(int、long、float、double)、布爾類型、null類型。

類型

示例

字符串

String str1 = parser.parseExpression("'Hello World!'").getValue(String.class);

String str2 = parser.parseExpression("\"Hello World!\"").getValue(String.class);

數字類型

int int1 = parser.parseExpression("1").getValue(Integer.class);

long long1 = parser.parseExpression("-1L").getValue(long.class);

float float1 = parser.parseExpression("1.1").getValue(Float.class);

double double1 = parser.parseExpression("1.1E+2").getValue(double.class);

int hex1 = parser.parseExpression("0xa").getValue(Integer.class);

long hex2 = parser.parseExpression("0xaL").getValue(long.class);

布爾類型

boolean true1 = parser.parseExpression("true").getValue(boolean.class);

boolean false1 = parser.parseExpression("false").getValue(boolean.class);

null類型

Object null1 = parser.parseExpression("null").getValue(Object.class);

?

二、算數運算表達式: SpEL支持加(+)、減(-)、乘(*)、除(/)、求余(%)、冪(^)運算。

類型

示例

加減乘除

int result1 = parser.parseExpression("1+2-3*4/2").getValue(Integer.class);//-3

求余

int result2 = parser.parseExpression("4%3").getValue(Integer.class);//1

冪運算

int result3 = parser.parseExpression("2^3").getValue(Integer.class);//8

SpEL還提供求余(MOD)和除(DIV)而外兩個運算符,與“%”和“/”等價,不區分大小寫。

?

三、關系表達式:等于(==)、不等于(!=)、大于(>)、大于等于(>=)、小于(<)、小于等于(<=),區間(between)運算,如“parser.parseExpression("1>2").getValue(boolean.class);”將返回false;而“parser.parseExpression("1 between {1, 2}").getValue(boolean.class);”將返回true。

?????? between運算符右邊操作數必須是列表類型,且只能包含2個元素。第一個元素為開始,第二個元素為結束,區間運算是包含邊界值的,即 xxx>=list.get(0) && xxx<=list.get(1)。

?????? SpEL同樣提供了等價的“EQ” 、“NE”、 “GT”、“GE”、 “LT” 、“LE”來表示等于、不等于、大于、大于等于、小于、小于等于,不區分大小寫。

?

四、邏輯表達式:且(and)、或(or)、非(!或NOT)。

?

java代碼: 查看復制到剪貼板打印
  • String?expression1?=?"2>1?and?(!true?or?!false)"; ??
  • boolean?result1?=?parser.parseExpression(expression1).getValue(boolean.class); ??
  • Assert.assertEquals(true,?result1); ??
  • ? ??
  • String?expression2?=?"2>1?and?(NOT?true?or?NOT?false)"; ??
  • boolean?result2?=?parser.parseExpression(expression2).getValue(boolean.class); ??
  • Assert.assertEquals(true,?result2);??
  • String expression1 = "2>1 and (!true or !false)"; boolean result1 = parser.parseExpression(expression1).getValue(boolean.class); Assert.assertEquals(true, result1);String expression2 = "2>1 and (NOT true or NOT false)"; boolean result2 = parser.parseExpression(expression2).getValue(boolean.class); Assert.assertEquals(true, result2);

    ?

    注:邏輯運算符不支持 Java中的 && 和 || 。

    ?

    五、字符串連接及截取表達式:使用“+”進行字符串連接,使用“'String'[0] [index]”來截取一個字符,目前只支持截取一個,如“'Hello ' + 'World!'”得到“Hello World!”;而“'Hello World!'[0]”將返回“H”。

    ?

    六、三目運算及Elivis運算表達式:

    三目運算符 “表達式1?表達式2:表達式3”用于構造三目運算表達式,如“2>1?true:false”將返回true;

    Elivis運算符“表達式1?:表達式2”從Groovy語言引入用于簡化三目運算符的,當表達式1為非null時則返回表達式1,當表達式1為null時則返回表達式2,簡化了三目運算符方式“表達式1? 表達式1:表達式2”,如“null?:false”將返回false,而“true?:false”將返回true;

    ?

    七、正則表達式:使用“str matches regex,如“'123' matches '\\d{3}'”將返回true;

    ?

    八、括號優先級表達式:使用“(表達式)”構造,括號里的具有高優先級。

    ?

    5.3.3? 類相關表達式

    一、類類型表達式:使用“T(Type)”來表示java.lang.Class實例,“Type”必須是類全限定名,“java.lang”包除外,即該包下的類可以不指定包名;使用類類型表達式還可以進行訪問類靜態方法及類靜態字段。

    ?????? ?具體使用方法如下:

    ?

    java代碼: 查看復制到剪貼板打印
  • @Test??
  • public?void?testClassTypeExpression()?{ ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????//java.lang包類訪問 ??
  • ????Class<String>?result1?=?parser.parseExpression("T(String)").getValue(Class.class); ??
  • ????Assert.assertEquals(String.class,?result1); ??
  • ????//其他包類訪問 ??
  • ????String?expression2?=?"T(cn.javass.spring.chapter5.SpELTest)"; ??
  • ????Class<String>?result2?=?parser.parseExpression(expression2).getValue(Class.class);????Assert.assertEquals(SpELTest.class,?result2); ??
  • ????//類靜態字段訪問 ??
  • ????int?result3=parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class); ??
  • ????Assert.assertEquals(Integer.MAX_VALUE,?result3); ??
  • ????//類靜態方法調用 ??
  • ????int?result4?=?parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class); ??
  • ????Assert.assertEquals(1,?result4); ??
  • }??
  • @Test public void testClassTypeExpression() {ExpressionParser parser = new SpelExpressionParser();//java.lang包類訪問Class<String> result1 = parser.parseExpression("T(String)").getValue(Class.class);Assert.assertEquals(String.class, result1);//其他包類訪問String expression2 = "T(cn.javass.spring.chapter5.SpELTest)";Class<String> result2 = parser.parseExpression(expression2).getValue(Class.class); Assert.assertEquals(SpELTest.class, result2);//類靜態字段訪問int result3=parser.parseExpression("T(Integer).MAX_VALUE").getValue(int.class);Assert.assertEquals(Integer.MAX_VALUE, result3);//類靜態方法調用int result4 = parser.parseExpression("T(Integer).parseInt('1')").getValue(int.class);Assert.assertEquals(1, result4); }

    ?

    ?????? 對于java.lang包里的可以直接使用“T(String)”訪問;其他包必須是類全限定名;可以進行靜態字段訪問如“T(Integer).MAX_VALUE”;也可以進行靜態方法訪問如“T(Integer).parseInt('1')”。

    ?

    二、類實例化:類實例化同樣使用java關鍵字“new”,類名必須是全限定名,但java.lang包內的類型除外,如String、Integer。

    ?

    java代碼: 查看復制到剪貼板打印
  • @Test??
  • public?void?testConstructorExpression()?{ ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????String?result1?=?parser.parseExpression("new?String('haha')").getValue(String.class); ??
  • ????Assert.assertEquals("haha",?result1); ??
  • ????Date?result2?=?parser.parseExpression("new?java.util.Date()").getValue(Date.class); ??
  • ????Assert.assertNotNull(result2); ??
  • }??
  • @Test public void testConstructorExpression() {ExpressionParser parser = new SpelExpressionParser();String result1 = parser.parseExpression("new String('haha')").getValue(String.class);Assert.assertEquals("haha", result1);Date result2 = parser.parseExpression("new java.util.Date()").getValue(Date.class);Assert.assertNotNull(result2); }

    ?

    ?????? 實例化完全跟Java內方式一樣。

    ?

    三、instanceof表達式:SpEL支持instanceof運算符,跟Java內使用同義;如“'haha' instanceof T(String)”將返回true。

    ?

    四、變量定義及引用:變量定義通過EvaluationContext接口的setVariable(variableName, value)方法定義;在表達式中使用“#variableName”引用;除了引用自定義變量,SpE還允許引用根對象及當前上下文對象,使用“#root”引用根對象,使用“#this”引用當前上下文對象;

    ?

    java代碼: 查看復制到剪貼板打印
  • ???? ??
  • @Test??
  • public?void?testVariableExpression()?{ ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????EvaluationContext?context?=?new?StandardEvaluationContext(); ??
  • ????context.setVariable("variable",?"haha"); ??
  • ????context.setVariable("variable",?"haha"); ??
  • ????String?result1?=?parser.parseExpression("#variable").getValue(context,?String.class); ??
  • ????Assert.assertEquals("haha",?result1); ??
  • ? ??
  • ????context?=?new?StandardEvaluationContext("haha"); ??
  • ????String?result2?=?parser.parseExpression("#root").getValue(context,?String.class); ??
  • ????Assert.assertEquals("haha",?result2); ??
  • ????String?result3?=?parser.parseExpression("#this").getValue(context,?String.class); ??
  • ????Assert.assertEquals("haha",?result3); ??
  • }??
  • @Test public void testVariableExpression() {ExpressionParser parser = new SpelExpressionParser();EvaluationContext context = new StandardEvaluationContext();context.setVariable("variable", "haha");context.setVariable("variable", "haha");String result1 = parser.parseExpression("#variable").getValue(context, String.class);Assert.assertEquals("haha", result1);context = new StandardEvaluationContext("haha");String result2 = parser.parseExpression("#root").getValue(context, String.class);Assert.assertEquals("haha", result2);String result3 = parser.parseExpression("#this").getValue(context, String.class);Assert.assertEquals("haha", result3); }

    ?

    ?????? 使用“#variable”來引用在EvaluationContext定義的變量;除了可以引用自定義變量,還可以使用“#root”引用根對象,“#this”引用當前上下文對象,此處“#this”即根對象。

    ?

    五、自定義函數:目前只支持類靜態方法注冊為自定義函數;SpEL使用StandardEvaluationContext的registerFunction方法進行注冊自定義函數,其實完全可以使用setVariable代替,兩者其實本質是一樣的;

    ?

    java代碼: 查看復制到剪貼板打印
  • @Test??
  • public?void?testFunctionExpression()?throws?SecurityException,?NoSuchMethodException?{ ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????StandardEvaluationContext?context?=?new?StandardEvaluationContext(); ??
  • ????Method?parseInt?=?Integer.class.getDeclaredMethod("parseInt",?String.class); ??
  • ????context.registerFunction("parseInt",?parseInt); ??
  • ????context.setVariable("parseInt2",?parseInt); ??
  • ????String?expression1?=?"#parseInt('3')?==?#parseInt2('3')"; ??
  • ????boolean?result1?=?parser.parseExpression(expression1).getValue(context,?boolean.class); ??
  • ????Assert.assertEquals(true,?result1);??????? ??
  • } ??
  • ???
  • @Test public void testFunctionExpression() throws SecurityException, NoSuchMethodException {ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext();Method parseInt = Integer.class.getDeclaredMethod("parseInt", String.class);context.registerFunction("parseInt", parseInt);context.setVariable("parseInt2", parseInt);String expression1 = "#parseInt('3') == #parseInt2('3')";boolean result1 = parser.parseExpression(expression1).getValue(context, boolean.class);Assert.assertEquals(true, result1); }

    ?????? 此處可以看出“registerFunction”和“setVariable”都可以注冊自定義函數,但是兩個方法的含義不一樣,推薦使用“registerFunction”方法注冊自定義函數。

    ?

    六、賦值表達式:SpEL即允許給自定義變量賦值,也允許給跟對象賦值,直接使用“#variableName=value”即可賦值:

    ?

    java代碼: 查看復制到剪貼板打印
  • @Test??
  • public?void?testAssignExpression()?{ ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????//1.給root對象賦值 ??
  • ????EvaluationContext?context?=?new?StandardEvaluationContext("aaaa"); ??
  • ????String?result1?=?parser.parseExpression("#root='aaaaa'").getValue(context,?String.class); ??
  • ????Assert.assertEquals("aaaaa",?result1); ??
  • ????String?result2?=?parser.parseExpression("#this='aaaa'").getValue(context,?String.class); ??
  • ????Assert.assertEquals("aaaa",?result2); ??
  • ? ??
  • ????//2.給自定義變量賦值 ??
  • ????context.setVariable("#variable",?"variable"); ??
  • ????String?result3?=?parser.parseExpression("#variable=#root").getValue(context,?String.class); ??
  • ????Assert.assertEquals("aaaa",?result3); ??
  • }??
  • @Test public void testAssignExpression() {ExpressionParser parser = new SpelExpressionParser();//1.給root對象賦值EvaluationContext context = new StandardEvaluationContext("aaaa");String result1 = parser.parseExpression("#root='aaaaa'").getValue(context, String.class);Assert.assertEquals("aaaaa", result1);String result2 = parser.parseExpression("#this='aaaa'").getValue(context, String.class);Assert.assertEquals("aaaa", result2);//2.給自定義變量賦值context.setVariable("#variable", "variable");String result3 = parser.parseExpression("#variable=#root").getValue(context, String.class);Assert.assertEquals("aaaa", result3); }

    ?????? 使用“#root='aaaaa'”給根對象賦值,使用“"#this='aaaa'”給當前上下文對象賦值,使用“#variable=#root”給自定義變量賦值,很簡單。

    ?

    七、對象屬性存取及安全導航表達式:對象屬性獲取非常簡單,即使用如“a.property.property”這種點綴式獲取,SpEL對于屬性名首字母是不區分大小寫的;SpEL還引入了Groovy語言中的安全導航運算符“(對象|屬性)?.屬性”,用來避免但“?.”前邊的表達式為null時拋出空指針異常,而是返回null;修改對象屬性值則可以通過賦值表達式或Expression接口的setValue方法修改。

    ?

    java代碼: 查看復制到剪貼板打印
  • ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • //1.訪問root對象屬性 ??
  • Date?date?=?new?Date(); ??
  • StandardEvaluationContext?context?=?new?StandardEvaluationContext(date); ??
  • int?result1?=?parser.parseExpression("Year").getValue(context,?int.class); ??
  • Assert.assertEquals(date.getYear(),?result1); ??
  • int?result2?=?parser.parseExpression("year").getValue(context,?int.class); ??
  • Assert.assertEquals(date.getYear(),?result2);?????????
  • ExpressionParser parser = new SpelExpressionParser(); //1.訪問root對象屬性 Date date = new Date(); StandardEvaluationContext context = new StandardEvaluationContext(date); int result1 = parser.parseExpression("Year").getValue(context, int.class); Assert.assertEquals(date.getYear(), result1); int result2 = parser.parseExpression("year").getValue(context, int.class); Assert.assertEquals(date.getYear(), result2);

    ?

    ?????? 對于當前上下文對象屬性及方法訪問,可以直接使用屬性或方法名訪問,比如此處根對象date屬性“year”,注意此處屬性名首字母不區分大小寫。

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • ???? ??
  • //2.安全訪問 ??
  • context.setRootObject(null); ??
  • Object?result3?=?parser.parseExpression("#root?.year").getValue(context,?Object.class); ??
  • Assert.assertEquals(null,?result3);??? ??
  • ???
  • //2.安全訪問 context.setRootObject(null); Object result3 = parser.parseExpression("#root?.year").getValue(context, Object.class); Assert.assertEquals(null, result3);

    ?

    ?????? SpEL引入了Groovy的安全導航運算符,比如此處根對象為null,所以如果訪問其屬性時肯定拋出空指針異常,而采用“?.”安全訪問導航運算符將不拋空指針異常,而是簡單的返回null。

    ?

    java代碼: 查看復制到剪貼板打印
  • //3.給root對象屬性賦值 ??
  • context.setRootObject(date); ??
  • int?result4?=?parser.parseExpression("Year?=?4").getValue(context,?int.class); ??
  • Assert.assertEquals(4,?result4); ??
  • parser.parseExpression("Year").setValue(context,?5); ??
  • int?result5?=?parser.parseExpression("Year").getValue(context,?int.class); ??
  • Assert.assertEquals(5,?result5); ??
  • ???
  • //3.給root對象屬性賦值 context.setRootObject(date); int result4 = parser.parseExpression("Year = 4").getValue(context, int.class); Assert.assertEquals(4, result4); parser.parseExpression("Year").setValue(context, 5); int result5 = parser.parseExpression("Year").getValue(context, int.class); Assert.assertEquals(5, result5);

    ? ? ? ?給對象屬性賦值可以采用賦值表達式或Expression接口的setValue方法賦值,而且也可以采用點綴方式賦值。

    ?

    八、對象方法調用:對象方法調用更簡單,跟Java語法一樣;如“'haha'.substring(2,4)”將返回“ha”;而對于根對象可以直接調用方法;

    ?

    java代碼: 查看復制到剪貼板打印
  • Date?date?=?new?Date(); ??
  • StandardEvaluationContext?context?=?new?StandardEvaluationContext(date); ??
  • int?result2?=?parser.parseExpression("getYear()").getValue(context,?int.class); ??
  • Assert.assertEquals(date.getYear(),?result2);??
  • Date date = new Date(); StandardEvaluationContext context = new StandardEvaluationContext(date); int result2 = parser.parseExpression("getYear()").getValue(context, int.class); Assert.assertEquals(date.getYear(), result2);

    ?

    ?????? 比如根對象date方法“getYear”可以直接調用。

    ?

    九、Bean引用:SpEL支持使用“@”符號來引用Bean,在引用Bean時需要使用BeanResolver接口實現來查找Bean,Spring提供BeanFactoryResolver實現;

    ?

    java代碼: 查看復制到剪貼板打印
  • @Test??
  • public?void?testBeanExpression()?{ ??
  • ????ClassPathXmlApplicationContext?ctx?=?new?ClassPathXmlApplicationContext(); ??
  • ????ctx.refresh(); ??
  • ????ExpressionParser?parser?=?new?SpelExpressionParser(); ??
  • ????StandardEvaluationContext?context?=?new?StandardEvaluationContext(); ??
  • ????context.setBeanResolver(new?BeanFactoryResolver(ctx)); ??
  • ????Properties?result1?=?parser.parseExpression("@systemProperties").getValue(context,?Properties.class); ??
  • ????Assert.assertEquals(System.getProperties(),?result1); ??
  • }??
  • @Test public void testBeanExpression() {ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext();ctx.refresh();ExpressionParser parser = new SpelExpressionParser();StandardEvaluationContext context = new StandardEvaluationContext();context.setBeanResolver(new BeanFactoryResolver(ctx));Properties result1 = parser.parseExpression("@systemProperties").getValue(context, Properties.class);Assert.assertEquals(System.getProperties(), result1); }

    ?

    ?????? 在示例中我們首先初始化了一個IoC容器,ClassPathXmlApplicationContext 實現默認會把“System.getProperties()”注冊為“systemProperties”Bean,因此我們使用 “@systemProperties”來引用該Bean。

    ?

    5.3.3? 集合相關表達式

    一、內聯List:從Spring3.0.4開始支持內聯List,使用{表達式,……}定義內聯List,如“{1,2,3}”將返回一個整型的ArrayList,而“{}”將返回空的List,對于字面量表達式列表,SpEL會使用java.util.Collections.unmodifiableList方法將列表設置為不可修改。

    ?

    java代碼: 查看復制到剪貼板打印
  • //將返回不可修改的空List ??
  • List<Integer>?result2?=?parser.parseExpression("{}").getValue(List.class);??
  • //將返回不可修改的空List List<Integer> result2 = parser.parseExpression("{}").getValue(List.class);

    ?

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //對于字面量列表也將返回不可修改的List ??
  • List<Integer>?result1?=?parser.parseExpression("{1,2,3}").getValue(List.class); ??
  • Assert.assertEquals(new?Integer(1),?result1.get(0)); ??
  • try?{ ??
  • ????result1.set(0,?2); ??
  • ????//不可能執行到這,對于字面量列表不可修改 ??
  • ????Assert.fail(); ??
  • }?catch?(Exception?e)?{ ??
  • }??
  • //對于字面量列表也將返回不可修改的List List<Integer> result1 = parser.parseExpression("{1,2,3}").getValue(List.class); Assert.assertEquals(new Integer(1), result1.get(0)); try {result1.set(0, 2);//不可能執行到這,對于字面量列表不可修改Assert.fail(); } catch (Exception e) { }

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //對于列表中只要有一個不是字面量表達式,將只返回原始List, ??
  • //不會進行不可修改處理 ??
  • String?expression3?=?"{{1+2,2+4},{3,4+4}}"; ??
  • List<List<Integer>>?result3?=?parser.parseExpression(expression3).getValue(List.class); ??
  • result3.get(0).set(0,?1); ??
  • Assert.assertEquals(2,?result3.size());??
  • //對于列表中只要有一個不是字面量表達式,將只返回原始List, //不會進行不可修改處理 String expression3 = "{{1+2,2+4},{3,4+4}}"; List<List<Integer>> result3 = parser.parseExpression(expression3).getValue(List.class); result3.get(0).set(0, 1); Assert.assertEquals(2, result3.size());

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //聲明二維數組并初始化 ??
  • int[]?result2?=?parser.parseExpression("new?int[2]{1,2}").getValue(int[].class);??
  • //聲明二維數組并初始化 int[] result2 = parser.parseExpression("new int[2]{1,2}").getValue(int[].class);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //定義一維數組并初始化 ??
  • int[]?result1?=?parser.parseExpression("new?int[1]").getValue(int[].class);??
  • //定義一維數組并初始化 int[] result1 = parser.parseExpression("new int[1]").getValue(int[].class);

    ?

    ?

    二、內聯數組:和Java 數組定義類似,只是在定義時進行多維數組初始化。

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • ???? ??
  • //定義多維數組但不初始化 ??
  • int[][][]?result3?=?parser.parseExpression(expression3).getValue(int[][][].class);??
  • //定義多維數組但不初始化 int[][][] result3 = parser.parseExpression(expression3).getValue(int[][][].class);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //錯誤的定義多維數組,多維數組不能初始化 ??
  • String?expression4?=?"new?int[1][2][3]{{1}{2}{3}}"; ??
  • try?{ ??
  • ????int[][][]?result4?=?parser.parseExpression(expression4).getValue(int[][][].class); ??
  • ????Assert.fail(); ??
  • }?catch?(Exception?e)?{ ??
  • }??
  • //錯誤的定義多維數組,多維數組不能初始化 String expression4 = "new int[1][2][3]{{1}{2}{3}}"; try {int[][][] result4 = parser.parseExpression(expression4).getValue(int[][][].class);Assert.fail(); } catch (Exception e) { }

    ?

    ?

    三、集合,字典元素訪問:SpEL目前支持所有集合類型和字典類型的元素訪問,使用“集合[索引]”訪問集合元素,使用“map[key]”訪問字典元素;

    ?

    java代碼: 查看復制到剪貼板打印
  • //SpEL內聯List訪問 ??
  • int?result1?=?parser.parseExpression("{1,2,3}[0]").getValue(int.class); ??
  • //即list.get(0) ??
  • Assert.assertEquals(1,?result1); ??
  • ???
  • //SpEL內聯List訪問 int result1 = parser.parseExpression("{1,2,3}[0]").getValue(int.class); //即list.get(0) Assert.assertEquals(1, result1);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //SpEL目前支持所有集合類型的訪問 ??
  • Collection<Integer>?collection?=?new?HashSet<Integer>(); ??
  • collection.add(1); ??
  • collection.add(2); ??
  • EvaluationContext?context2?=?new?StandardEvaluationContext(); ??
  • context2.setVariable("collection",?collection); ??
  • int?result2?=?parser.parseExpression("#collection[1]").getValue(context2,?int.class); ??
  • //對于任何集合類型通過Iterator來定位元素 ??
  • Assert.assertEquals(2,?result2);??
  • //SpEL目前支持所有集合類型的訪問 Collection<Integer> collection = new HashSet<Integer>(); collection.add(1); collection.add(2); EvaluationContext context2 = new StandardEvaluationContext(); context2.setVariable("collection", collection); int result2 = parser.parseExpression("#collection[1]").getValue(context2, int.class); //對于任何集合類型通過Iterator來定位元素 Assert.assertEquals(2, result2);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //SpEL對Map字典元素訪問的支持 ??
  • Map<String,?Integer>?map?=?new?HashMap<String,?Integer>(); ??
  • map.put("a",?1); ??
  • EvaluationContext?context3?=?new?StandardEvaluationContext(); ??
  • context3.setVariable("map",?map); ??
  • int?result3?=?parser.parseExpression("#map['a']").getValue(context3,?int.class); ??
  • Assert.assertEquals(1,?result3);??
  • //SpEL對Map字典元素訪問的支持 Map<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 1); EvaluationContext context3 = new StandardEvaluationContext(); context3.setVariable("map", map); int result3 = parser.parseExpression("#map['a']").getValue(context3, int.class); Assert.assertEquals(1, result3);

    ?

    ?????? 注:集合元素訪問是通過Iterator遍歷來定位元素位置的

    ?

    ?

    四、列表,字典,數組元素修改:可以使用賦值表達式或Expression接口的setValue方法修改;

    ?

    java代碼: 查看復制到剪貼板打印
  • //1.修改數組元素值 ??
  • int[]?array?=?new?int[]?{1,?2}; ??
  • EvaluationContext?context1?=?new?StandardEvaluationContext(); ??
  • context1.setVariable("array",?array); ??
  • int?result1?=?parser.parseExpression("#array[1]?=?3").getValue(context1,?int.class); ??
  • Assert.assertEquals(3,?result1);??
  • //1.修改數組元素值 int[] array = new int[] {1, 2}; EvaluationContext context1 = new StandardEvaluationContext(); context1.setVariable("array", array); int result1 = parser.parseExpression("#array[1] = 3").getValue(context1, int.class); Assert.assertEquals(3, result1);

    ?

    ??

    java代碼: 查看復制到剪貼板打印
  • //2.修改集合值 ??
  • Collection<Integer>?collection?=?new?ArrayList<Integer>(); ??
  • collection.add(1); ??
  • collection.add(2); ??
  • EvaluationContext?context2?=?new?StandardEvaluationContext(); ??
  • context2.setVariable("collection",?collection); ??
  • int?result2?=?parser.parseExpression("#collection[1]?=?3").getValue(context2,?int.class); ??
  • Assert.assertEquals(3,?result2); ??
  • parser.parseExpression("#collection[1]").setValue(context2,?4); ??
  • result2?=?parser.parseExpression("#collection[1]").getValue(context2,?int.class); ??
  • Assert.assertEquals(4,?result2);??
  • //2.修改集合值 Collection<Integer> collection = new ArrayList<Integer>(); collection.add(1); collection.add(2); EvaluationContext context2 = new StandardEvaluationContext(); context2.setVariable("collection", collection); int result2 = parser.parseExpression("#collection[1] = 3").getValue(context2, int.class); Assert.assertEquals(3, result2); parser.parseExpression("#collection[1]").setValue(context2, 4); result2 = parser.parseExpression("#collection[1]").getValue(context2, int.class); Assert.assertEquals(4, result2);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //3.修改map元素值 ??
  • Map<String,?Integer>?map?=?new?HashMap<String,?Integer>(); ??
  • map.put("a",?1); ??
  • EvaluationContext?context3?=?new?StandardEvaluationContext(); ??
  • context3.setVariable("map",?map); ??
  • int?result3?=?parser.parseExpression("#map['a']?=?2").getValue(context3,?int.class); ??
  • Assert.assertEquals(2,?result3);??
  • //3.修改map元素值 Map<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 1); EvaluationContext context3 = new StandardEvaluationContext(); context3.setVariable("map", map); int result3 = parser.parseExpression("#map['a'] = 2").getValue(context3, int.class); Assert.assertEquals(2, result3);

    ?

    ?????? 對數組修改直接對“#array[index]”賦值即可修改元素值,同理適用于集合和字典類型。

    ?

    五、集合投影:在SQL中投影指從表中選擇出列,而在SpEL指根據集合中的元素中通過選擇來構造另一個集合,該集合和原集合具有相同數量的元素;SpEL使用“(list|map).![投影表達式]”來進行投影運算:

    ?

    java代碼: 查看復制到剪貼板打印
  • //1.首先準備測試數據 ??
  • Collection<Integer>?collection?=?new?ArrayList<Integer>(); ??
  • collection.add(4);???collection.add(5); ??
  • Map<String,?Integer>?map?=?new?HashMap<String,?Integer>(); ??
  • map.put("a",?1);????map.put("b",?2);??
  • //1.首先準備測試數據 Collection<Integer> collection = new ArrayList<Integer>(); collection.add(4); collection.add(5); Map<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 1); map.put("b", 2);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //2.測試集合或數組 ??
  • EvaluationContext?context1?=?new?StandardEvaluationContext(); ??
  • context1.setVariable("collection",?collection); ??
  • Collection<Integer>?result1?= ??
  • parser.parseExpression("#collection.![#this+1]").getValue(context1,?Collection.class); ??
  • Assert.assertEquals(2,?result1.size()); ??
  • Assert.assertEquals(new?Integer(5),?result1.iterator().next()); ??
  • ?????????
  • //2.測試集合或數組 EvaluationContext context1 = new StandardEvaluationContext(); context1.setVariable("collection", collection); Collection<Integer> result1 = parser.parseExpression("#collection.![#this+1]").getValue(context1, Collection.class); Assert.assertEquals(2, result1.size()); Assert.assertEquals(new Integer(5), result1.iterator().next());

    ?

    ? ? ? ?對于集合或數組使用如上表達式進行投影運算,其中投影表達式中“#this”代表每個集合或數組元素,可以使用比如“#this.property”來獲取集合元素的屬性,其中“#this”可以省略。

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //3.測試字典 ??
  • EvaluationContext?context2?=?new?StandardEvaluationContext(); ??
  • context2.setVariable("map",?map); ??
  • List<Integer>?result2?= ??
  • parser.parseExpression("#map.![?value+1]").getValue(context2,?List.class); ??
  • Assert.assertEquals(2,?result2.size());??
  • //3.測試字典 EvaluationContext context2 = new StandardEvaluationContext(); context2.setVariable("map", map); List<Integer> result2 = parser.parseExpression("#map.![ value+1]").getValue(context2, List.class); Assert.assertEquals(2, result2.size());

    ?

    ?????? SpEL投影運算還支持Map投影,但Map投影最終只能得到List結果,如上所示,對于投影表達式中的“#this”將是Map.Entry,所以可以使用“value”來獲取值,使用“key”來獲取鍵。

    ?

    ?

    六、集合選擇:在SQL中指使用select進行選擇行數據,而在SpEL指根據原集合通過條件表達式選擇出滿足條件的元素并構造為新的集合,SpEL使用“(list|map).?[選擇表達式]”,其中選擇表達式結果必須是boolean類型,如果true則選擇的元素將添加到新集合中,false將不添加到新集合中。

    ?

    java代碼: 查看復制到剪貼板打印
  • //1.首先準備測試數據 ??
  • Collection<Integer>?collection?=?new?ArrayList<Integer>(); ??
  • collection.add(4);???collection.add(5); ??
  • Map<String,?Integer>?map?=?new?HashMap<String,?Integer>(); ??
  • map.put("a",?1);????map.put("b",?2);??
  • //1.首先準備測試數據 Collection<Integer> collection = new ArrayList<Integer>(); collection.add(4); collection.add(5); Map<String, Integer> map = new HashMap<String, Integer>(); map.put("a", 1); map.put("b", 2);

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //2.集合或數組測試 ??
  • EvaluationContext?context1?=?new?StandardEvaluationContext(); ??
  • context1.setVariable("collection",?collection); ??
  • Collection<Integer>?result1?= ??
  • parser.parseExpression("#collection.?[#this>4]").getValue(context1,?Collection.class); ??
  • Assert.assertEquals(1,?result1.size()); ??
  • Assert.assertEquals(new?Integer(5),?result1.iterator().next());??
  • //2.集合或數組測試 EvaluationContext context1 = new StandardEvaluationContext(); context1.setVariable("collection", collection); Collection<Integer> result1 = parser.parseExpression("#collection.?[#this>4]").getValue(context1, Collection.class); Assert.assertEquals(1, result1.size()); Assert.assertEquals(new Integer(5), result1.iterator().next());

    ?

    ?????? 對于集合或數組選擇,如“#collection.?[#this>4]”將選擇出集合元素值大于4的所有元素。選擇表達式必須返回布爾類型,使用“#this”表示當前元素。

    ?

    ?

    java代碼: 查看復制到剪貼板打印
  • //3.字典測試 ??
  • EvaluationContext?context2?=?new?StandardEvaluationContext(); ??
  • context2.setVariable("map",?map); ??
  • Map<String,?Integer>?result2?= ??
  • parser.parseExpression("#map.?[#this.key?!=?'a']").getValue(context2,?Map.class); ??
  • Assert.assertEquals(1,?result2.size()); ??
  • ? ??
  • List<Integer>?result3?= ??
  • ?parser.parseExpression("#map.?[key?!=?'a'].![value+1]").getValue(context2,?List.class); ??
  • Assert.assertEquals(new?Integer(3),?result3.iterator().next());??
  • //3.字典測試 EvaluationContext context2 = new StandardEvaluationContext(); context2.setVariable("map", map); Map<String, Integer> result2 = parser.parseExpression("#map.?[#this.key != 'a']").getValue(context2, Map.class); Assert.assertEquals(1, result2.size());List<Integer> result3 =parser.parseExpression("#map.?[key != 'a'].![value+1]").getValue(context2, List.class); Assert.assertEquals(new Integer(3), result3.iterator().next());

    ?

    ?????? 對于字典選擇,如“#map.?[#this.key != 'a']”將選擇鍵值不等于”a”的,其中選擇表達式中“#this”是Map.Entry類型,而最終結果還是Map,這點和投影不同;集合選擇和投影可以一起使用,如“#map.?[key != 'a'].![value+1]”將首先選擇鍵值不等于”a”的,然后在選出的Map中再進行“value+1”的投影。

    ?

    5.3.4? 表達式模板

    ?????? 模板表達式就是由字面量與一個或多個表達式塊組成。每個表達式塊由“前綴+表達式+后綴”形式組成,如“${1+2}”即表達式塊。在前邊我們已經介紹了使用ParserContext接口實現來定義表達式是否是模板及前綴和后綴定義。在此就不多介紹了,如“Error ${#v0} ${#v1}”表達式表示由字面量“Error ”、模板表達式“#v0”、模板表達式“#v1”組成,其中v0和v1表示自定義變量,需要在上下文定義。

    ?

    總結

    以上是生活随笔為你收集整理的Spring 3.0参考之SpEL的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    亚洲精品一区二区三区高潮 | 国产一区二区在线看 | 四虎www| 亚洲国产三级在线 | 欧美日韩久久 | 国产原创在线 | 手机看片国产日韩 | 韩国在线视频一区 | www黄| 久久国产午夜精品理论片最新版本 | 综合色伊人 | avove黑丝 | 超碰99人人| 91精品在线免费视频 | 日韩在线视| 国产黄大片在线观看 | 亚洲乱码在线观看 | 色诱亚洲精品久久久久久 | 97精品国自产拍在线观看 | 四虎国产精品成人免费影视 | 久久久久亚洲精品成人网小说 | 韩国av一区二区三区在线观看 | 国产精品一区二区久久国产 | 中文字幕一区二区三区在线视频 | 精品久久久久久久久久国产 | 中文字幕乱码日本亚洲一区二区 | 国产精品伦一区二区三区视频 | 中国黄色一级大片 | 久久人人爽人人爽人人片av软件 | 成年人在线观看视频免费 | 中文字幕在线专区 | 国产1区在线 | 婷婷精品国产一区二区三区日韩 | 久久免费av电影 | www.久草.com | 国产精品视频免费观看 | 正在播放日韩 | 国产精品欧美激情在线观看 | 有没有在线观看av | 69精品视频在线观看 | 婷婷丁香在线视频 | 国产精品免费大片视频 | 久草久草久草久草 | 久久精品国产久精国产 | 国产一区二区在线观看视频 | 色欧美88888久久久久久影院 | 天天综合日日夜夜 | 人人插人人看 | 国产精品久久久电影 | 中文字幕二区 | 久久综合九色综合久99 | 91成人欧美| 国产精品中文 | 亚洲黄色片在线 | 欧美日韩中文国产一区发布 | 国产糖心vlog在线观看 | 亚洲一区美女视频在线观看免费 | 国产精品久久久久久久久久久久午夜 | 人人添人人澡人人澡人人人爽 | 成人免费观看完整版电影 | 国产 日韩 欧美 自拍 | 久久久99精品免费观看乱色 | h网站免费在线观看 | 久久综合九色综合欧美狠狠 | 玖玖999 | 黄p在线播放 | 美女视频久久黄 | 国产精品久久久电影 | 九色91视频| 国产精品美女免费视频 | 亚洲成a人片综合在线 | 91成人精品一区在线播放69 | 久久久国产在线视频 | 一本大道久久精品懂色aⅴ 五月婷社区 | 97夜夜澡人人爽人人免费 | 色综合天天射 | 成人黄色片免费看 | 国产视频欧美视频 | 日本在线观看黄色 | 日韩a在线看 | 午夜三级毛片 | 91香蕉国产 | 精品国产自 | 亚洲一区二区三区四区在线视频 | 日本中文字幕一二区观 | 午夜精品电影一区二区在线 | 欧美精品天堂 | 国产精品大片在线观看 | 97香蕉超级碰碰久久免费软件 | 91精品视屏 | 97av免费视频| 欧美日韩一区二区三区免费视频 | 最近中文字幕在线 | 成人动漫一区二区三区 | 精品国产观看 | 黄色国产成人 | 探花视频在线观看+在线播放 | 中文字幕91在线 | 欧美一二区在线 | 九九精品在线观看 | 国产在线精品视频 | 国产无限资源在线观看 | 一级做a爱片性色毛片www | 精品在线看| 国产精品久久久久久久久久久免费看 | 99日精品 | 99九九视频 | 国产高清一区二区 | а中文在线天堂 | 久久资源总站 | 日韩欧美在线第一页 | aaa毛片视频| 色噜噜在线观看 | 国产在线成人 | 黄p网站在线观看 | 日韩av不卡在线 | 国产精品久久一区二区无卡 | 亚洲国产精品影院 | 手机av电影在线观看 | 伊人狠狠色 | 中文字幕国产一区 | 一二三精品视频 | 国产群p | 91精品免费视频 | av中文电影 | 98精品国产自产在线观看 | 91九色成人蝌蚪首页 | 国内毛片毛片 | 久爱精品在线 | 狠狠色丁香婷婷综合橹88 | 白丝av免费观看 | 亚洲天堂自拍视频 | 国产小视频你懂的在线 | 97日日碰人人模人人澡分享吧 | 日日夜日日干 | 99热这里| 国产精品一区专区欧美日韩 | 国产精品免费久久久久影院仙踪林 | av成人在线观看 | 国产99久久精品一区二区永久免费 | 久久久麻豆精品一区二区 | 亚洲精品99久久久久久 | 午夜18视频在线观看 | 中文字幕888 | 亚洲一区欧美激情 | 91亚色在线观看 | 国产色a在线观看 | 国产色在线,com| 99久久精品久久亚洲精品 | 在线播放第一页 | 日韩欧美91 | 在线婷婷 | 久草网免费| 色资源在线 | 日韩激情一二三区 | 九九热免费视频在线观看 | 欧美激情综合五月 | 免费高清男女打扑克视频 | www.色婷婷.com | 国产精品毛片久久蜜 | 免费看成人a | 日日碰夜夜爽 | 久久狠狠一本精品综合网 | 九九热精品视频在线观看 | 视频在线在亚洲 | 国产精品大片 | 国产激情小视频在线观看 | 狠狠操影视 | 黄色av电影网 | 一级性视频 | 免费观看一区 | 久久激情电影 | 色网站在线免费 | 欧美日韩在线免费观看 | 欧美日韩国产精品一区二区 | 超碰伊人网 | 久久天天躁夜夜躁狠狠85麻豆 | 中文在线www| 亚洲国产精品久久久久 | 久久艹精品 | 日韩在线第一区 | 国产成人不卡 | 国产精品精品国产色婷婷 | 五月婷在线播放 | 亚洲国产午夜 | 国内视频在线 | 人人狠狠综合久久亚洲婷 | 日韩一区精品 | 国产一区二区免费看 | 亚洲综合视频在线 | 日韩亚洲在线视频 | 色综合久久久久久久久五月 | 亚州日韩中文字幕 | 精品国产一区二区三区在线 | 国产欧美最新羞羞视频在线观看 | 日韩成人免费在线观看 | 97在线观看免费高清完整版在线观看 | 怡红院av久久久久久久 | 久久久久国产成人免费精品免费 | 成人av手机在线 | 亚洲区精品 | 国产精品美女久久久久久久久 | 久久免费黄色 | 97av在线视频 | 久久国内视频 | 麻豆系列在线观看 | 日本视频高清 | 亚洲日本va中文字幕 | 色狠狠综合 | av电影免费在线 | 国产成人精品午夜在线播放 | 91精品国产成人观看 | 日韩系列 | 久久永久视频 | 免费观看一区二区 | 国产午夜精品免费一区二区三区视频 | 97在线精品国自产拍中文 | 成人免费一级片 | 久久深夜福利免费观看 | 久久婷婷色 | 久久久www成人免费毛片 | 国产精品18久久久久久久 | 免费色视频在线 | 天天干干| 午夜视频黄 | 国产亚洲精品日韩在线tv黄 | 91成人精品国产刺激国语对白 | 91麻豆精品91久久久久同性 | 久久久蜜桃一区二区 | 国产群p视频 | 国产成人一区二区啪在线观看 | 久草网免费 | 久久国产精品久久w女人spa | 久久激情五月激情 | 一区二区精品在线视频 | 五月香婷 | 干综合网 | 夜夜狠狠| 亚洲免费精彩视频 | 国产午夜三级一区二区三 | 国产精品第一页在线 | 韩国一区在线 | 免费视频网 | 国产精品v欧美精品 | 婷婷社区五月天 | 国产美女永久免费 | 日韩欧美91| 久久精品久久99精品久久 | 麻豆免费在线播放 | 亚洲精品国产第一综合99久久 | 欧美激情精品 | 国产视频在线观看一区 | 亚洲精品综合在线 | 玖玖视频| 亚洲 欧洲 国产 日本 综合 | 国产精品99久久久久久小说 | 啪啪动态视频 | 国产成人一二三 | 国产一线二线三线性视频 | 天天爱天天射天天干天天 | 久久久香蕉视频 | 国内精品久久久久久久影视麻豆 | 色网站国产精品 | 字幕网在线观看 | 国产精品精品久久久久久 | 最新中文字幕在线观看视频 | 色综合久久久久综合 | 九九九九精品九九九九 | 97热视频 | 成人在线免费视频观看 | 98久久| 成人在线视频网 | 丰满少妇一级片 | 久久久久久久久久久福利 | 亚洲欧美日韩精品久久奇米一区 | 六月丁香激情网 | 中文字幕在线免费观看视频 | 人人爽夜夜爽 | 亚洲精品毛片一级91精品 | 色天堂在线视频 | 伊人久久国产精品 | 精品天堂av| 久草视频在线免费看 | 亚洲精品乱码 | 狠狠干干| 中文字幕av免费 | 最新av在线免费观看 | 成人免费在线播放视频 | 国产激情久久久 | 欧美国产高清 | 日本黄区免费视频观看 | 亚洲最大激情中文字幕 | 中文字幕一二 | 日韩网站在线观看 | 国产亚洲在 | 久久免费在线观看视频 | 日韩av不卡播放 | 日韩av看片| 国产精品高清一区二区三区 | 狠狠干夜夜爽 | 色噜噜在线观看视频 | 亚洲精品久久久蜜桃 | 国产一区二区不卡视频 | 成人在线免费观看视视频 | 国产精品免费久久 | 日韩爱爱片 | 97成人免费 | 天天干天天碰 | 97在线精品视频 | 国产精品99久久久久久人免费 | 最近日韩免费视频 | 国产精品免费小视频 | 亚洲精品国产成人 | 成人在线免费av | 欧美一区在线看 | 亚洲高清不卡av | 精品在线视频播放 | 成人午夜电影网站 | 麻豆一区在线观看 | 高清免费在线视频 | 婷婷www| 免费在线黄网 | 国产精品一区二区av日韩在线 | 日本久久精品视频 | 色视频 在线 | 亚洲一区二区三区精品在线观看 | 国产在线91精品 | 97超级碰碰 | 中文字幕乱视频 | 一区二区三区在线观看免费 | 国产成人在线免费观看 | 五月婷婷综合久久 | 国产视频丨精品|在线观看 国产精品久久久久久久久久久久午夜 | 欧美日韩精品影院 | 日本不卡久久 | 胖bbbb搡bbbb擦bbbb| 少妇av网 | 激情五月亚洲 | 亚洲成人av片在线观看 | 国产高清免费在线播放 | 伊人视频 | 热热热热热色 | 国产精品久久久一区二区 | 天天干,天天操,天天射 | 在线不卡中文字幕播放 | 中文字幕国产在线 | 国产视频久久久 | 日韩视频一区二区三区在线播放免费观看 | 久久免费试看 | 亚州精品在线视频 | zzijzzij亚洲日本少妇熟睡 | 亚洲色五月 | 成人免费色| 久久综合99| 久久久免费精品国产一区二区 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 91av电影在线观看 | 久草久热 | 99精品免费在线观看 | 久久婷婷一区二区三区 | 欧美精品久久久久久久免费 | 国产精品久久久av久久久 | 黄色毛片大全 | 97超碰在线资源 | 久久久久免费精品国产 | 四虎8848免费高清在线观看 | 99精品欧美一区二区蜜桃免费 | 久久免费播放视频 | 精品国产区在线 | 日韩免费在线播放 | 日日综合| 九色视频网址 | 韩日成人av | 日韩欧美精品在线 | 久久久久久久久久久久久国产精品 | 成人av免费网站 | 丁香五婷| 免费亚洲视频 | 日韩一级理论片 | 一区在线电影 | 国产黄色观看 | 久久国产麻豆 | 婷婷久月 | 91免费观看国产 | 99久久精品免费看国产 | 国产精品18久久久久久vr | 色www精品视频在线观看 | 亚洲成av人片在线观看无 | 国产精品区在线观看 | 久久一级电影 | 探花视频在线观看免费 | 天天做天天爱天天爽综合网 | 999久久国产精品免费观看网站 | 久久婷婷视频 | 精品视频一区在线 | 中文字幕国产精品 | 久久99亚洲精品久久 | 激情综合站| 国产精品美乳一区二区免费 | 欧美日韩精品在线播放 | 亚洲性xxxx | 日日夜夜免费精品 | 婷婷六月综合网 | 国产成人一区二区精品非洲 | 中文字幕欧美日韩va免费视频 | 四虎在线永久免费观看 | 欧美日韩视频在线观看一区二区 | 婷婷久久综合网 | 欧美色图亚洲图片 | 菠萝菠萝在线精品视频 | 一级欧美一级日韩 | 欧美综合久久 | 久久久资源 | 日韩专区av | 免费精品在线观看 | 日韩激情一二三区 | 中文字幕乱码电影 | 国产91免费看 | 成人av资源在线 | 久久国产精品免费视频 | www.亚洲视频 | 亚洲国产精品久久久 | 成人h电影在线观看 | 又大又硬又黄又爽视频在线观看 | 天天射天 | 精品一二三四五区 | 99热精品国产一区二区在线观看 | 免费在线观看午夜视频 | 国产99久久九九精品 | 美女福利视频一区二区 | www夜夜 | 日韩激情在线视频 | 五月婷婷开心中文字幕 | 麻豆91在线看 | 亚洲综合五月 | 亚洲精品国产成人 | 丁香激情网| 国内精品久久久精品电影院 | 毛片基地黄久久久久久天堂 | 国产尤物视频在线 | 国产精品九九久久99视频 | 精品久久久久免费极品大片 | 国产精品影音先锋 | 九九视频网站 | 香蕉一区| 蜜臀久久99精品久久久无需会员 | 日韩资源视频 | 天天综合天天做天天综合 | 九九有精品| 91自拍视频在线观看 | 天天天干天天天操 | 黄色网www | 不卡视频在线看 | 亚洲欧洲av在线 | 国产一区二区高清 | 中文字幕日韩在线播放 | 黄色免费电影网站 | 婷婷丁香激情综合 | 成人小视频在线播放 | 国产剧情在线一区 | 69视频在线 | 日韩大片免费在线观看 | 国内精品久久久久久久久久清纯 | 国产一区av在线 | 国产一二三精品 | 欧美性生交大片免网 | 天天草av | 欧美激情视频在线观看免费 | 欧美在线视频一区二区三区 | 又爽又黄又无遮挡网站动态图 | 最新三级在线 | 亚洲精品影视在线观看 | 国产在线黄色 | 粉嫩高清一区二区三区 | 国产精品精品视频 | 日韩成人免费在线观看 | 97超碰伊人| 亚洲综合在| 欧美男同视频网站 | 久久影院午夜论 | 国产手机视频在线播放 | 久久成人麻豆午夜电影 | 久久久久久片 | 国产成人av片 | 一区二区三区电影 | 日本资源中文字幕在线 | 麻豆国产视频下载 | 国产特级毛片aaaaaaa高清 | 中文字幕在线观看的网站 | 91亚洲激情| 九九热免费在线观看 | 91久久国产综合精品女同国语 | 国产精在线| 在线激情网| 91成人免费看 | 热久久视久久精品18亚洲精品 | 国产精品一区二区久久 | 国产69精品久久99不卡的观看体验 | 亚洲香蕉在线观看 | 国产精品日韩在线 | 毛片基地黄久久久久久天堂 | av网站免费线看精品 | 欧美日韩99| 亚洲va在线va天堂va偷拍 | 一区二区三区在线视频111 | 久草视频手机在线 | 中文字幕在线观看第二页 | 亚洲一区二区精品在线 | 久久免费试看 | 四虎永久国产精品 | 在线观看视频福利 | 国产精品免费一区二区 | 亚洲精品美女久久久久 | 99视频免费看 | 国产999精品久久久久久 | 高清久久久久久 | 日本性视频| 日韩一区二区三区高清在线观看 | 久久久2o19精品 | 国产一级二级三级视频 | 五月天九九 | 午夜精品福利一区二区三区蜜桃 | 日本精品小视频 | 欧美精品一区二区性色 | 精品福利在线 | 欧美成人视 | 国产精品完整版 | 中文字幕专区高清在线观看 | 国产黄色在线看 | 久艹视频在线免费观看 | 亚洲人成人天堂h久久 | 亚洲国产成人av网 | 国产一级在线视频 | 国产成人精品在线播放 | 国产精品久久久久久高潮 | 国产欧美日韩视频 | www.888av | 久久久久久久亚洲精品 | www.精选视频.com| 91视频 - x99av | 五月天色综合 | 91禁在线观看 | 黄污网| 激情综合网天天干 | 日韩欧美国产成人 | 久久久久久久福利 | 永久黄网站色视频免费观看w | 久久99九九99精品 | 欧美激情精品久久 | 久久久亚洲影院 | 日本性久久 | 亚洲一区动漫 | 久久成人精品电影 | 91桃色免费观看 | 亚洲91精品在线观看 | 91成人网页版 | 国产精品久久久久久久久久久免费 | 久久伊人操 | 午夜成人免费电影 | 日韩午夜在线播放 | 欧美91精品国产自产 | 亚洲精品视频网站在线观看 | 欧美坐爱视频 | 1000部18岁以下禁看视频 | 色婷婷丁香 | 视频1区2区 | 久久视精品 | 久久亚洲区 | 成人在线视频免费看 | aaa日本高清在线播放免费观看 | 亚洲精品动漫成人3d无尽在线 | 久久成人综合视频 | 中文字幕视频观看 | 毛片1000部免费看 | 又长又大又黑又粗欧美 | 丁香婷婷深情五月亚洲 | 国产成人一区二区三区影院在线 | 亚洲视频在线看 | 视频一区在线播放 | 国产成人三级 | 午夜精品区 | 午夜影院先 | 国产久草在线观看 | 亚洲精品乱码 | 婷婷丁香在线观看 | 99免费在线播放99久久免费 | 超碰av在线 | 日本久久久久 | 久久综合在线 | 五月婷婷婷婷婷 | 日韩中文字幕免费在线播放 | 免费看黄的视频 | 丰满少妇在线观看 | 美女一二三区 | 九九久久精品视频 | 国产精品成人av在线 | 一本一本久久a久久精品牛牛影视 | 婷婷久操 | 91视频在线自拍 | 日日夜夜精品免费视频 | 国产vs久久 | 国产精品免费久久久久久 | 国产h在线观看 | 国产在线观看免费 | 狠狠色丁香婷婷综合久久片 | 精品欧美一区二区精品久久 | 中文av在线播放 | 永久免费视频国产 | 在线国产能看的 | 婷婷在线观看视频 | 国产福利免费在线观看 | 免费观看国产成人 | 深夜国产在线 | 九色视频网址 | 少妇视频一区 | 中文字幕在线观看网 | 黄色小说视频在线 | 97高清视频| 国产视| www黄色com| 青青色影院 | 热久久免费视频 | 国产一级精品绿帽视频 | 婷婷综合成人 | 久草视频在线播放 | 久草视频手机在线 | 一区在线观看 | 99久久精品电影 | 亚洲干 | 亚洲3级 | 在线观看视频在线观看 | 在线播放国产精品 | 在线观看完整版免费 | 日韩综合一区二区三区 | 中文字幕久久精品一区 | 在线观看91精品国产网站 | 国产无遮挡猛进猛出免费软件 | 香蕉久久久久久av成人 | 久久久99久久 | 一区二区三区韩国免费中文网站 | 亚州欧美视频 | 日韩精品在线观看视频 | 黄色免费观看 | 美女av免费 | 中午字幕在线 | 综合色婷婷 | 欧美资源在线观看 | 成人资源站 | 精品视频区 | 欧美亚洲国产精品久久高清浪潮 | 草久在线观看 | 午夜国产福利在线观看 | 国产一级大片免费看 | 99 色 | 麻豆视频免费在线观看 | 久久视| 国产又粗又硬又长又爽的视频 | 国产一区二区精 | 国产亚洲成人精品 | 免费一级日韩欧美性大片 | 美女视频是黄的免费观看 | 日韩视频精品在线 | 欧美色噜噜 | 在线观看黄色免费视频 | 玖玖在线播放 | 激情综合电影网 | 欧美激情第一区 | 黄网站色欧美视频 | 日韩免费小视频 | 亚洲欧美视频在线观看 | 免费在线观看成人 | 久久综合中文色婷婷 | 久久99国产精品久久99 | 亚洲欧美成人综合 | 天天干com | av高清在线 | 国产成在线观看免费视频 | 人人看看人人 | 爱爱av网站| 欧美一级免费黄色片 | 日韩视频在线不卡 | 伊人狠狠干 | 激情av综合 | 日日夜夜精品网站 | 欧美aaa一级| 欧美性大战 | 欧美精品一二 | 人人爽人人爽人人片av免 | 国产精品成人免费一区久久羞羞 | 91一区二区在线 | 人人草网站| 亚洲综合激情网 | 国产在线观看国语版免费 | 97精品国产97久久久久久久久久久久 | 国产麻豆成人传媒免费观看 | 中文字幕视频免费观看 | 日韩久久久久久久久 | 亚洲国产精品999 | 久久不见久久见免费影院 | 国产午夜三级一区二区三桃花影视 | 亚洲第一区在线播放 | 黄色片网站 | 欧美日韩啪啪 | 97在线观看免费高清完整版在线观看 | 日韩精品一区二区三区免费观看视频 | 欧美特一级 | 九九热视频在线免费观看 | 日本精品中文字幕 | 日韩久久久久久久久久 | 成人国产精品入口 | 69av在线视频 | 国产成人免费观看久久久 | 婷婷五天天在线视频 | 亚洲精品福利在线观看 | 中文字幕色在线 | 4438全国亚洲精品在线观看视频 | 日韩欧美在线中文字幕 | 日韩精品一区二区免费视频 | 黄色三级免费网址 | 免费黄色激情视频 | 日韩中文字幕亚洲一区二区va在线 | 日日干夜夜干 | 久久久久久久久久网 | 97av视频 | 国内视频| 日韩免费二区 | 日韩免费一区 | 一区二区三区在线观看免费 | 日本精品视频免费观看 | 精品国产日本 | 久久撸在线视频 | 粉嫩一区二区三区粉嫩91 | 天堂av免费看 | 久久久久久久av麻豆果冻 | 天天躁日日躁狠狠 | 日韩中文字幕网站 | 四虎4hu永久免费 | 国产视频 亚洲精品 | 久久午夜精品视频 | 西西4444www大胆艺术 | 麻豆视频入口 | av片无限看 | 日韩免费在线观看 | 久久精视频 | 日本黄色一级电影 | 天天射色综合 | 亚洲精品综合在线观看 | 国产打女人屁股调教97 | 成人黄色国产 | 特级黄色片免费看 | 国产艹b视频| 国产成人三级 | 国产黄色一级大片 | 久久综合欧美精品亚洲一区 | 91私密视频 | 91一区二区在线 | 久久经典视频 | 中文字幕有码在线播放 | 国产精品日韩在线 | 五月婷婷在线视频观看 | 欧美疯狂性受xxxxx另类 | 999视频网站 | 久久欧洲视频 | 国产高清无线码2021 | 久久精品一区二区三区四区 | 91日韩在线 | 亚洲精品高清视频 | 精品久久电影 | 久99久久| 福利视频导航网址 | 亚洲精品黄| 中文字幕在线观看的网站 | 在线a人v观看视频 | 中文免费观看 | 伊人狠狠色| 国产精品美女免费 | 国产精品国产三级国产aⅴ无密码 | 国产欧美精品一区二区三区 | 日本精品视频在线播放 | a v在线观看| 久久久伦理| 国产精品美女久久久久久2018 | 亚洲乱亚洲乱亚洲 | 在线有码中文字幕 | 久久精品视频免费观看 | 免费观看www7722午夜电影 | 欧美日韩国产一区二区三区在线观看 | 免费的国产精品 | 91成人看片 | 国产精品视频免费观看 | 国内精品久久久久 | 激情综合网色播五月 | 国产无遮挡又黄又爽在线观看 | 中文网丁香综合网 | 亚洲区视频在线 | 福利一区二区三区四区 | 日韩精品大片 | 亚洲影视九九影院在线观看 | 最新超碰| 久久综合99| 欧美日韩xxx | 免费精品人在线二线三线 | 亚洲在线a | 91精品久久久久久久久久久久久 | 久久999精品| 久久久久高清毛片一级 | 欧美a在线免费观看 | 99在线高清视频在线播放 | 在线视频99 | 91av综合| 日日噜噜噜噜夜夜爽亚洲精品 | 天堂v中文| 黄色小网站在线 | 97超视频在线观看 | 中文字幕视频播放 | 久久国产精品一国产精品 | 97色综合 | 国产又黄又硬又爽 | 久热国产视频 | 91超级碰碰| 亚洲国产欧美在线人成大黄瓜 | 月丁香婷婷 | 亚洲精品国久久99热 | av片中文| 久久成| 日韩一区在线播放 | 国产中文| 免费视频 你懂的 | 国产免费a| 操操操夜夜操 | 国产高清精品在线观看 | 免费看av在线 | 亚洲人成免费网站 | 亚洲最新av网站 | 久久综合色8888 | 国产对白av | 999成人免费视频 | 日本中文字幕在线一区 | 人人澡人人添人人爽一区二区 | 国产九色视频在线观看 | 国产高清99 | 女人高潮特级毛片 | 18久久久久久 | 婷婷丁香国产 | 国产九色在线播放九色 | 91精品视频免费看 | 国产呻吟在线 | 欧美日本三级 | 福利一区二区 | 日本乱码在线 | 五月天综合网站 | 亚洲欧美偷拍另类 | 99精品电影 | 最新极品jizzhd欧美 | 超碰个人在线 | 波多野结衣在线视频免费观看 | 中文字幕视频播放 | www.操.com| 久久久综合电影 | 欧美极品少妇xbxb性爽爽视频 | 99久久久国产精品免费观看 | 免费看黄在线看 | 在线亚洲欧美视频 | 狠狠色狠狠色合久久伊人 | www.777奇米| 在线看免费 | 国产又粗又猛又色 | 婷婷在线网| 中文字幕一区2区3区 | 国产主播大尺度精品福利免费 | 激情六月婷婷久久 | 天天色天天 | 精品亚洲成人 | av高清网站在线观看 | 超碰97中文 | 狠狠狠狠狠狠狠狠 | 91日韩在线视频 | 欧美日韩在线视频观看 | 日韩精品中文字幕一区二区 | 精品久久久久久国产91 | 天天操夜夜看 | 日产乱码一二三区别在线 | 日韩精品无 | 久久高清精品 | av色影院| 伊人激情综合 | 久草男人天堂 | 欧美人交a欧美精品 | avlulu久久精品 | 免费能看的黄色片 | av在线免费网站 | 久久国产精品久久国产精品 | 亚洲永久精品一区 | 国产手机视频在线播放 | 免费视频久久久 | av大片免费看 | 国产福利一区二区三区在线观看 | 国产一级特黄电影 | 三级黄色免费 | 日韩中文字幕一区 | 91成人精品在线 | 久久99电影 | av丝袜美腿| 国产午夜精品一区二区三区 | 麻豆91精品 | 一区二区三区手机在线观看 | 激情一区二区三区欧美 | 亚洲一区二区视频在线播放 | 最近更新的中文字幕 | 在线观看91精品视频 | 亚洲精品国产综合久久 | 91手机视频 | 国产剧情av在线播放 | 狠狠色狠狠色综合系列 | 国产精品99久久久久久久久 | 在线视频app | 超碰成人免费电影 | 久久99亚洲精品久久久久 | 欧美日韩久久不卡 | 中文字幕在线观看第三页 | 狠狠五月天 | 在线观看免费视频你懂的 | 久久公开视频 | 国产精久久 | 国产精品入口麻豆 | 日韩在线视频线视频免费网站 | 国产视频精品在线 | 国产综合激情 | 九九九九热精品免费视频点播观看 | 久久国产手机看片 | 婷婷免费视频 | 欧美亚洲三级 | 亚洲综合在线一区二区三区 | 夜夜狠狠 | 欧美日韩一区二区视频在线观看 | 久久久久久久久久久久亚洲 | 超碰激情在线 | 日韩中文在线视频 | 最近中文字幕视频网 | 最新国产精品拍自在线播放 | 免费观看国产精品 | 97超碰在线资源 | 久久久免费观看完整版 | 四虎影视成人 | 婷婷色站| 日本动漫做毛片一区二区 | 麻豆国产精品一区二区三区 | .国产精品成人自产拍在线观看6 | 狠狠色噜噜狠狠狠合久 | av免费网站在线观看 | 91久久丝袜国产露脸动漫 | 高清一区二区三区av | 视频一区二区在线 | 色噜噜狠狠狠狠色综合 | 人人射人人澡 | 福利视频网站 | 亚洲国产中文字幕 | 国产精品va在线观看入 | av片中文字幕 | 综合久久精品 | 黄色免费高清视频 | 久久成人亚洲欧美电影 | 日韩成人精品在线观看 | 日本精品久久久久久 | 伊人色综合网 | 久久r精品 | 免费在线色 | 中文在线中文资源 | 99理论片| 天堂在线一区二区三区 | 亚洲精品在线观看中文字幕 | 81国产精品久久久久久久久久 | 久久久久高清毛片一级 | 国产成人精品一区二区三区福利 | 99在线热播 | 色多多在线观看 | 日韩最新av| 麻豆一二三精选视频 | 成人 国产 在线 | 日韩激情视频在线观看 | 亚洲一区动漫 | 免费视频91蜜桃 | 国产精品丝袜在线 | 久久精品国亚洲 | 69精品久久久 | 日韩av网址在线 | 久久久精品视频成人 | 91中文字幕视频 | 99日精品| 69精品人人人人 | 成人久久免费 | 欧美日韩精品在线播放 | 国产亚洲精品福利 | 在线观看一区二区视频 | 精品av在线播放 | 波多野结衣资源 | 天天综合在线观看 | 欧美日韩另类视频 |