第5章解密Struts之核心文件在第4章中简单介绍了JavaWeb开发的三大框架之一的Struts2框架的一些基本概念及其开发的流程.
在Struts2项目开发中,有一个重要的过程就是其配置文件的配置.
本章将介绍Struts核心配置文件的具体作用及其配置方式,然后介绍Struts2框架中的另一种文件——Action类文件,本章的主要内容如下:配置文件web.
xml.
配置文件struts.
properties.
配置文件struts.
xml.
Action类文件.
5.
1Struts配置文件之web.
xml本节介绍Struts2框架中的web.
xml配置文件,先介绍该文件的主要作用,然后对该文件中的关键元素进行分析.
web.
xml文件中包含了大量的标签元素,这些元素都对应着各自不同的功能.
web.
xml文件中的元素种类繁多,但读者不需要记住所有的,只需要掌握一些常用的标签元素即可.
5.
1.
1web.
xml的主要作用不管是基于MVC框架的struts2框架,还是基于Servlet的纯JSP工程,只要开发者想要开发JavaWeb的程序,就不得不学习web.
xml文件的相关知识.
所以,web.
xml是Struts2框架中一个非常重要的配置文件,对Web应用中一些初始信息进行了配置.
Struts2框架要先依赖于过滤器FilterDispatcher来截获Web程序的HTTP请求,再做进一步的处理.
这就必须在web.
xml文件中来配置FilterDispatcher过滤器.
web.
xml除了用来配置过滤器外,还可以用来配置会话时间、欢迎页、错误页、监听器、控制器等等.
web.
xml文件中含有一系列标签元素,这些标签元素代表了不同的功能,读者需要掌握其中一些基本的用法.
web.
xml文件中可以包含哪些元素是由其对应的Schema文件来定义的.
因此,必须在每个web.
xml文件的根元素web-app中指定其Schema文件的版本.
web.
xml的Schema文件由Sun公司定义.
010205.
.
.
06在上面代码的第1行定义了XML文件的版本和编码方式,接着在标签中(即第2~6行)指明了Schema文件的来源.
当需要添加其他标签时,应该将其加入到标签之间(即第5行省略部分).
5.
1.
2web.
xml关键元素分析下面对web.
xml中的常用元素做一下介绍.
1.
welcome-file-list和welcome-file元素在访问一个网站时,用户看到的第一个页面就是欢迎页面.
通常,欢迎页面都在web.
xml中指定,但在一个Web工程中web.
xml并不是必须存在的.
随着Web应用的功能越来越复杂,web.
xml逐渐变得日益重要,因此,一般在Eclipse中创建动态Web工程时都让其为我们自动生成一个web.
xml文件.
如果在访问Web应用时,只指定了一个根名,而没有指定具体的页面或Action,那么Tomcat就会查看web.
xml中是否指定了欢迎页面,如果指定了,则访问此欢迎页面;否则,Tomcat默认会去查找index.
html和index.
jsp页面;如果这两个页面也不存在,就会报错.
在web.
xml文件中,welcome-file-list和welcome-file元素就是用来指定欢迎页面的,welcome-file-list元素可以包含多个welcome-file元素,每个welcome-file元素指定一个欢迎页面.
如下代码所示:a.
jspb.
jsp在上面代码中,Tomcat会按顺序来查找欢迎页面,即如果Web应用中存在a.
jsp,则它就是欢迎页面,否则继续查找b.
jsp.
2.
filter和filter-mapping元素filter元素用于声明一个过滤器,使用该元素可以同时拦截多个请求的URL.
filter-mapping元素用来指定与过滤器关联的URL,代码如下:struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilter第5章解密Struts之核心文件·125·struts2/*上面代码中标签中的"/*"表明该过滤器可以拦截所有的HTTP请求.
3.
error-page元素虽然Struts框架提供了通用的错误处理机制,但是并不能保证对所有错误和异常都能进行处理.
如果Struts框架不能处理某种错误,就会把它抛给Web容器来处理.
默认情况下,Web容器会将原始的错误信息返回给用户浏览器,如HTTP404错误.
如果不希望用户看到原始的错误信息,就可以在web.
xml文件的error-page元素中进行配置.
还可以通过配置error-page元素来捕获Java异常,此时需要设置exception-type子元素来指定Java异常类.
error-page元素用来指定错误处理页面.
可以通过配置错误码元素error-code以避免用户直接看到原始错误信息.
还可以配置异常类型元素exception-type来指定Java中的异常类,代码如下:404/error.
jspjava.
lang.
Exception/error.
jsp4.
listener元素该元素用来注册监听器类,并使用子元素listener-class指定监听程序的完整限定类名,下面的代码设置了监听器,用于初始化Spring框架:org.
springframework.
web.
context.
ContextLoaderListener5.
session-config元素该元素用来指定会话过期时间,下面代码表示会话时间超过30分钟,session对象里面存放的值会自动失效:第2篇表现层框架Struts技术·126·30通常,该元素用在需要记录用户登录状态的时间的应用中,将用户登录的关键信息放入session对象中.
如果用户登录的时间超过配置的时间,该信息就会丢失,这样用户就需要重新登录.
因此,使用该元素可以保证用户的登录安全.
6.
init-param元素该元素用来定义参数,在web.
xml中可以有多个init-param元素.
下面的代码使用init-param元素设置了常量:struts.
i18n.
encodingUTF-8【例5-1】本例说明web.
xml配置文件的使用方式.
(1)首先在Eclipse中创建一个新工程ErrorPage,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中.
在WEB-INF目录下创建web.
xml文件,打开web.
xml并写入如下代码:struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp404/error.
jsp(2)在WebContent目录下创建index.
jsp﹑error.
jsp文件,分别打开并编写代码,核心代码如下.
第5章解密Struts之核心文件·127·index.
jsp核心代码:helloerror.
jsp核心代码:thepageyourequestisnotexisting!
(3)运行程序,结果如图5.
1所示,单击链接后,出现如图5.
2所示的页面.
图5.
1例5-1运行结果图5.
2单击链接后在这个例子中,由于没有配置struts.
xml等文件,单击链接时会发生错误,其错误码是404,根据web.
xml文件中的配置,会转到error.
jsp页面.
读者需要注意的是,当Web应用程序运行过程中出错时,会有对应的HTTP状态码与出现的错误相匹配,Web服务器根据状态码就会返回相应的页面.
此处由于在web.
xml中配置了404错误的错误处理页面为error.
jsp,所以会转到error.
jsp;否则,会转到Web服务器定义的404页面.
404错误码表示用户访问的页面不存在,除此以外还有其他一些常用的HTTP状态码如下所示:200:服务器成功返回网页.
404:请求的网页不存在.
503:服务不可用.
403:Forbidden(禁止),服务器拒绝请求.
408:RequestTimeout(请求超时),服务器等候请求时发生超时.
413:RequestEntityTooLarge(请求实体过大),服务器无法处理请求,因为请求实体过大,超出服务器的处理能力.
414:Request-URITooLong(请求的URI过长),请求的URI(通常为网址)过长,服务器无法处理.
415:UnsupportedMediaType(不支持的媒体类型),请求的格式不受请求页面的支持.
416:RequestedRangeNotSatisfiable(请求范围不符合要求),如果页面无法提供请求的范围,则服务器会返回此状态代码.
第2篇表现层框架Struts技术·128·417:ExpectationFailed(未满足期望值),服务器未满足"期望"请求标头字段的要求.
500:InternalServerError(服务器内部错误),服务器遇到错误,无法完成请求.
501:NotImplemented(尚未实施),服务器不具备完成请求的功能.
例如,服务器无法识别请求方法时可能会返回此代码.
502:BadGateway(错误网关),服务器作为网关或代理,从上游服务器收到无效响应.
503:ServiceUnavailable(服务不可用),服务器目前无法使用(由于超载或停机维护).
通常,这只是暂时状态.
504:GatewayTimeout(网关超时),服务器作为网关或代理,但是没有及时从上游服务器收到请求.
505:HTTPVersionNotSupported(HTTP版本不受支持),服务器不支持请求中所用的HTTP协议版本.
5.
2Struts配置文件之struts.
properties在5.
1节介绍了Struts2框架中的一个配置文件web.
xml,本节将介绍Struts2中的struts.
properties配置文件.
先介绍struts.
properties文件的主要作用,然后对文件中的关键元素进行详细分析.
在Struts工程的开发中,需要用到大量的属性,这些属性大多在默认的配置文件中已经配置好,但根据用户需求的不同,开发的要求也不同,可能需要更改这些属性值,改变这些属性值的方法就是在struts.
properties文件中来配置即可.
5.
2.
1struts.
properties的主要作用struts.
properties是Struts2框架中一个重要的配置文件,程序员可以通过它来管理Struts2框架中定义的大量常量.
struts.
properties文件是一个标准的properties文件,其格式是key-value对,即每个key对应一个value,key表示的是Struts2框架中的常量,而value则是其常量值.
struts.
properties文件必须放到Web应用下的类加载路径下才能使用,即WEB-INF/classes路径下.
在Eclipse中,由于编译时,Eclipse会自动将src路径下的struts.
properties文件编译后放到WEB-INF∕classes路径下,所以,通常直接将其放到src路径下就可以了.
前面说过,struts.
properties是一个key-value文件,所以其格式比较简单,下面是struts.
properties文件的代码片段:###设置默认编码集为UTF-8格式struts.
i18n.
encoding=UTF-8###设置使用开发模式struts.
devMode=true###设置默认的local为en_USstruts.
locale=en_US第5章解密Struts之核心文件·129·5.
2.
2struts.
properties关键元素分析下面介绍一些常用的Struts2常量:struts.
i18n.
encoding:该常量指定了Web应用中的默认编码集.
通常,由于使用中文字符集,将其设置为UTF-8.
struts.
devMode:该常量指定Struts2是否使用开发模式.
当值设为true时,表示使用开发模式,可以在应用程序出错时显示更详细的出错提示.
其默认值为false.
通常,在开发阶段,建议使用开发模式;当产品发布后,则可将该常量设置为false.
struts.
configuration:该常量指定Struts2框架的配置管理器,如果程序员要开发自己的配置管理器,需实现一个Configuration接口的类,该类会自己加载Struts2配置文件.
struts.
locale:该常量指定Web应用的默认Locale,默认的Locale是en_US.
struts.
action.
extension:该常量指定由Struts2处理的请求后缀.
程序员可以根据需要设置,默认的后缀是action,要设置多个请求后缀时要用逗号隔开.
struts.
tag.
altSyntax:该常量指定是否在Struts2标签中使用表达式语法,一般设置为true.
struts.
ui.
theme:该常量指定视图中Struts2标签默认的主题,默认值是xhtml.
struts.
custom.
i18n.
resources:该常量指定Web应用所需要的国际化资源文件,多个文件名用逗号隔开.
struts.
custom.
properties:该常量指定加载附加的配置文件的位置.
struts.
enable.
DynamicMethodInvocation:该常量指定Struts2框架是否支持动态方法调用,默认值为true,如果要关闭动态方法调用,设置该常量为false.
struts.
i18n.
reload:该常量指定国际化信息是否自动加载,默认值为true,如果不自动加载国际化信息,则设置该常量为false.
struts.
url.
http.
port:该常量指定Web应用的端口.
以上只对一部分常用的常量进行了介绍,读者如果想了解更多Struts2常量的内容,可以查阅相关资料.
5.
3Struts配置文件之struts.
xml在5.
2节中介绍了struts.
xml配置文件,本节将介绍Struts2框架中的struts.
xml配置文件,先介绍struts.
xml文件的主要作用,然后对该文件中的关键元素进行分析.
实际上,在开发Struts项目的过程中,struts.
xml文件的使用频率和web.
xml文件差不多,二者都在Struts项目中得到了广泛的运用.
所以,struts.
xml文件是开发Struts项目所必须掌握的.
5.
3.
1struts.
xml的主要作用和struts.
properties一样,struts.
xml也是Struts2框架中一个重要的配置文件,其存放第2篇表现层框架Struts技术·130·路径和struts.
properties一样,位于WEB-INF/classes路径下.
struts.
xml文件主要用来配置Action和HTTP请求的对应关系,以及配置逻辑视图和物理视图资源的对应关系.
但除了这些功能之外,struts.
xml文件还有一些额外的功能,如配置常量、导入其他配置文件等.
相比struts.
properties文件格式,struts.
xml文件配置的格式复杂得多.
下面的代码是struts.
xml文件最基本的配置:/YY.
jsp在上面代码中,是根标签,所有其他的标签都放在中间;package元素定义了一个包,在Struts2框架中,用包来组织Action和拦截器等,每个包都是零个或多个拦截器以及Action所组成的集合;action元素定义了一个Action和其对应的类;result元素定义了Action返回结果对应的JSP视图.
5.
3.
2struts.
xml关键元素分析下面对struts.
xml的相关内容进行详细介绍.
1.
几个重要的元素(1)package元素package元素用来配置包.
在Struts2框架中,包是一个独立的单位,通过name属性来唯一标识包.
还可以通过指定extends属性让一个包继承另一个包,extends属性值就是被继承包的name属性值,继承包可以从被继承包那里继承到拦截器、Action等.
此外,Struts2还提供了abstract属性,表示该包是一个抽象包,抽象包中不能有Action的定义.
package元素的属性如表5.
1所示.
表5.
1package元素属性属性说明name这是一个必须属性,标识包的名字,以便在其他包中被引用extends可选属性,指定该包继承自其他包namespace可选属性,指定命名空间,标识此包下的Action的访问路径abstract可选属性,指定该包为抽象包第5章解密Struts之核心文件·131·在表5.
1中可以看到,package元素有一个namespace属性,该属性可以指定包对应的命名空间.
由于在一个Web应用中可能出现同名的Action并存的情况,为了避免命名冲突,只要使同名Action位于不同的namespace下就可以了.
如果package元素没有指定namespace属性,则其下定义的所有Action都处于默认的命名空间下.
下面以一个示例来说明package命名空间属性的用法:/login_success.
jsp/exit_success.
jsp/stu_info.
jsp在上面代码中,配置了两个包:A和B.
对于包A,由于没指定命名空间,则其命名空间为默认命名空间;对于包B,其命名空间是根命名空间;对于包C,其命名空间则是"∕info".
当包指定命名空间后,该包所包含的Action处理的URL应该就是命名空间+Action名.
即包A下名为login的Action处理的URL是http://localhost:8080/login.
action;包B下名为exit的Action处理的URL是http://localhost:8080/exit.
action;包C下名为stu的Action处理的URL是http://localhost:8080/info/stu.
action,其中8080是笔者的Tomcat服务器的端口号.
对于URL中指定的Action,Struts2是按一定的顺序来查找的.
如果要访问/C/stu_info.
action,Struts2框架首先查找/C命名空间里名为stu_info的Action,如果该命名空间里找到对应的Action,则使用其对应的Action来处理请求;否则,Struts2框架到默认命名空间查找名为stu_info的Action,如果找到,则使用其对应的Action来处理请求;如果两个命名空间里都找不到名为stu_info的Action,则系统出现错误.
另外,读者有两个要注意的地方:第一,根命名空间和普通命名空间中的Action的查找是一样的,即如果有请求/stu_info.
action,则先查找根命名空间下的Action,如果不存在对应的Action,则查找默认命名空间里的Action.
第二,对于多级别的命名空间,Struts2框架在最底层的命名空间里查找后,如果不存在相应的Action,则会同样到默认命名空间里查找,而不是到上一级命名空间里查找.
即如果请求为/A/A_Login/login.
action时,Struts2框架首先到/A/A_Login的命名空间里查找名为login的Action,如果找不到对应的Action,则会到默认命名空间里查找,而不是到/A的命名空间里查找.
(2)action元素Struts2框架通过Action对象来处理HTTP请求,该请求的URL地址对应的Action即第2篇表现层框架Struts技术·132·配置在action元素中,如下代码所示:/user.
jspaction元素除了有name和class属性外,还有method和converter属性,表5.
2列出了action元素的各个属性.
表5.
2action元素属性属性说明name这是一个必须属性,标识Acton,指定了该Action所处理的请求的URLclass可选属性,指定Action对象对应的实现类method可选属性,指定请求Action时调用的方法converter可选属性,指定类型转换器的类在配置action元素时,如果没有指定class属性值,则其默认值为类com.
opensymphony.
xwork2.
ActionSupport,该默认类会使用默认的处理方法execute()来处理请求.
实际上,execute()方法不会做任何处理而直接返回success值.
在配置action元素时,如果指定method属性值,则该Action可以调用method属性中指定的方法,而不是默认的execute()法.
(3)result元素当调用Action方法处理结束返回后,下一步就是使用result元素来设置返回给浏览器的视图.
配置result元素时常需指定name和type两个属性.
name属性对应从Action方法返回的值,success为其默认值.
type属性指定结果类型,默认的类型是dispatcher,Struts2支持的结果类型如表5.
3所示.
表5.
3Struts2支持的结果类型结果类型说明dispatcher将请求forward(转发)到指定的JSP页面redirect将请求重定向到指定的视图资源chain处理Action链freemarker指定使用Freemarker模板作为视图httpheader控制特殊的HTTP行为redirect-action直接跳转到其他Actionstream向浏览器返回一个InputStream(一般用于文件下载)velocity指定使用velocity模板作为视图xslt用于XML/XSLT整合plainText显示某个页面的原始代码读者需要注意的是dispatcher和redirect的区别,也就是转发和重定向的区别,重定向会丢失所有的请求参数,而且会丢失Action的处理结果.
此处先介绍redirect和redirect-action这两种结果类型,其他一些常用类型会在后续章节进行介绍.
①redirect类型redirect结果类型与dispatcher结果类型刚好是相反的,初学者在使用时容易将它们混第5章解密Struts之核心文件·133·淆.
dispatcher结果类型表示将HTTP请求转发到指定的JSP资源,redirect结果类型则是将请求重定向到JSP资源,而重定向的结果则会丢失所有的请求参数和Action的处理结果.
②redirect-action类型redirect-action结果类型主要用于当一个Action处理结束后,将请求重定向到另一个Action.
它和redirect结果类型一样,会重新生成一个新请求,而且Action处理结果及请求的所有参数都会丢失,只是redirect-action结果类型生成的请求是一个Action,而redirect结果类型生成的请求是一个JSP资源.
【例5-2】本例说明redirect-action结果类型的用法.
(a)在Eclipse创建一个JavaWeb项目,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中,然后在WEB-INF目录下添加web.
xml文件,并在其中注册过滤器和欢迎页面.
web.
xml文件代码如下所示:struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp(b)在src目录下创建包com.
action,在该包下创建LoginAction.
java和UserAction.
java文件,这两个文件的代码如下所示.
LoginAction.
java代码如下:packagecom.
action;importcom.
opensymphony.
xwork2.
ActionSupport;publicclassLoginActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;//重载execute()方法,返回SUCCESSpublicStringexecute()throwsException{returnSUCCESS;}//redirect()方法,返回ERRORpublicStringredirect()throwsException{returnERROR;}}第2篇表现层框架Struts技术·134·UserAction.
java代码如下:packagecom.
action;importcom.
opensymphony.
xwork2.
ActionSupport;publicclassUserActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;//重载execute()方法,返回SUCCESSpublicStringexecute()throwsException{//TODOAuto-generatedmethodstubreturnSUCCESS;}}(c)在src目录下创建struts.
xml文件,代码如下:userLogin/usererror/error.
jsp/hello.
jsp(d)在WebContent目录下创建文件index.
jsp﹑hello.
jsp和error.
jsp,核心代码如下所示.
index.
jsp文件核心代码如下:loginredirecthello.
jsp文件核心代码如下:第5章解密Struts之核心文件·135·helloerror.
jsp文件核心代码如下:error(e)运行程序,结果如图5.
3所示,单击login链接后,返回如图5.
4所示的页面;单击redirect链接后,返回如图5.
5所示的页面.
图5.
3例5-2运行结果图5.
4单击login链接后图5.
5单击redirect链接后第2篇表现层框架Struts技术·136·在这个例子中,读者应该注意到redirect结果类型的运用有两种方式:一是直接在标签后添加Action名称,二是运用标签的方式来指定Action.
这两种方式都可以达到同样的效果,可以根据需要选用.
(4)include元素该元素用来在一个struts.
xml配置文件中包含其他的配置文件.
默认情况下,当查找Action时,Struts2框架只会加载struts.
xml配置文件,但是当系统规模增大到一定的程度时,系统中的Action数量也会大大增加,这将会导致一个struts.
xml配置文件中包含大量的Action,显然不方便开发者进行编辑.
通过标签,可以将Action以模块的方式来加以管理,即将存在相关性的Action放到同一个xml文件中,然后通过在struts.
xml文件中配置标签来将它们组合在一起.
使用include元素的struts.
xml文件片段如下所示:需要注意的是,这些模块化的xml文件也必须是标准的Struts2配置文件,即必须包含头信息以及根元素等.
通常,Struts2框架的所有配置文件都放在WEB-INF/classes路径下,由于struts.
xml文件中配置了标签,则可以将其对应包含的文件信息加载进来.
(5)global-results元素该元素配置包中的全局结果,其代码示例如下所示.
在该代码示例中配置了一个全局结果,这个全局结果的作用范围为包下面所有Action.
当一个Action处理用户请求后返回时,会首先在该Action本身的局部结果中进行搜索,如果局部结果中没有对应的结果,则会查找全局结果.
/SUCCESS.
jsp/hello.
jsp(6)default-action-ref元素该元素用来配置默认的Action,即如果Struts2找不到对应的Action时,就会使用默认的Action来处理用户请求.
第5章解密Struts之核心文件·137·…在以上代码中,default-action-ref元素仅有一个name属性,该name属性指向一个Action,这个Action将成为默认的Action.
2.
Action的动态调用(DMI)在前面介绍的标签的使用中,Action对象对URL请求的处理都是调用其默认的execute()方法,对于单一的业务逻辑请求,这种方式或许适合.
但是,在实际的项目开发中,业务请求的类型的方法是多种多样的,即对同一个Action可能有不同的请求,通过创建多个Action能够解决这个问题,但是会使程序更复杂,且要编写更多的代码.
如果请求的方式有很多种,可以在execute()方法中通过判断请求的业务逻辑类型来转发到相应的处理方法中,这也是一种解决方案.
Struts2提供了这种包含多个处理逻辑的Action处理方式,即DMI(DynamicMethodInvocation,动态方法调用).
通过动态请求Action对象中的方法,可以实现对某一业务逻辑的处理.
DMI处理方式是通过请求Action对象中的一个具体的方法来实现动态的操作.
具体说就是,在请求Action的URL地址后加上请求方法字符串,与Action对象中的方法进行匹配.
其中,Action对象名称和方法之间用"!
"隔开.
即如果在struts.
xml文件中配置了名为user的Action,为了请求change()方法,请求方式应表示为"/user!
change.
action".
【例5-3】本例创建一个工程来说明DMI的使用.
(1)在Eclipse中创建一个JavaWeb项目DMIDemo,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中,然后在WEB-INF目录下添加web.
xml文件,并在其中注册过滤器和欢迎页面.
web.
xml文件代码如下所示:struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp第2篇表现层框架Struts技术·138·(2)在src目录下创建com.
action包,并在该包中创建类UserAction,其代码如下:packagecom.
action;importcom.
opensymphony.
xwork2.
ActionSupport;publicclassUserActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;privateStringinfo;//info属性//info属性的getter方法publicStringgetInfo(){returninfo;}//info属性的setter方法publicvoidsetInfo(Stringinfo){this.
info=info;}//重载execute()方法publicStringexecute()throwsException{info="hello,world";return"hello";}//update()方法,更新info属性publicStringupdate()throwsException{info="ok,updated";return"update";}}(3)在WebContent目录下创建index.
jsp、hello.
jsp和update.
jsp文件.
index.
jsp文件:helloupdatehello.
jsp文件:update.
jsp文件:(4)在src目录下创建struts.
xml文件.
第5章解密Struts之核心文件·139·/hello.
jsp/update.
jsp(5)运行程序,结果如图5.
6、图5.
7和图5.
8所示.
图5.
6test2工程图5.
7单击"hello"页面图5.
8单击"update"页面第2篇表现层框架Struts技术·140·注意:在单击update链接后,请求交给update()方法进行处理,这时浏览器的地址栏变为http://localhost:8080/test2/user!
update.
action.
由上例可以看到,Action请求的处理方式并非一定要通过execute()方法来处理,使用DMI方式常常更加方便灵活.
实际上,在现实的项目开发中,可以将同模块的一些请求封装在同一个Action中,使用DMI方式来处理不同的请求.
3.
通配符在实际的项目开发中,会出现多个Action定义的绝大部分都是相同的情况,这时就会产生大量冗余.
对于这种情况,Struts2也给出了相应的解决方法,即使用通配符.
这种配置方式可以通过一定的命名约定来配置Action对象,以达到简化定义的效果.
在struts.
xml文件中,通配符主要指的是"*"、"**"和"\".
通配符"*"匹配0个或多个字符但不包含"/";通配符"**"匹配0个或多个字符包含"/";通配符"\"则是一个转义字符,即匹配字符"\"时,用"\\"来匹配.
具体说明如表5.
4所示.
表5.
4通配符说明通配符说明*匹配0个或多个字符除了"/"**匹配0个或多个字符包含"/"\character转义字符,"\\"匹配"\";"\*"匹配"*"通配符"*"通常用在标签的name属性中,而在class、name属性及result元素中使用{N}的形式来代表前面第N个*所匹配的字符串,{0}来代表URL请求的整个Action字符串.
下面举例来说明通配符的使用,示例代码如下:/{0}Suc.
jsp在上面的代码中,当URL请求是/update_Login.
action时,的name属性中第一个*匹配update,第二个*匹配Login,所以对应的会调用LoginAction类中的update()方法.
在结果映射中的记号是{0},则该记号会被整个URL代替,所以返回页面是update_LoginSuc.
jsp.
读者需要注意的是URL请求时的匹配顺序,即当有多个Action能和URL请求匹配时,最后会调用哪个Action.
在Struts2框架中,在查找匹配的Action时,首先会查找完全匹配的Action,然后会按照匹配的Action在struts.
xml文件中出现的顺序来匹配,即最前面的匹配的Action会被调用.
例如,struts.
xml文件中配置了3个Action,其name属性值分别是XAction﹑*Action和*,如果请求是XAction,则不管name属性值是XAction的Action出现的前后顺序,都会调用该Action中对应的方法;如果请求YAction,则会根据name属性值为*Action和*的这两个Action出现的顺序,来决定最后调用的Action.
第5章解密Struts之核心文件·141·在Struts2框架应用中,通配符有一个常用的使用方式,如下代码所示:{0}.
jsp上面代码中的Action没有指定class属性,则该Action会使用ActionSupport类来处理请求(后面会详细讲解),而该Action类会直接返回success字符串,则指定的JSP资源就是{0}.
jsp所代表的JSP资源.
该Action的含义是不管请求哪个Action,都会返回与该Action名字相同的JSP页面.
通过这种方式,避免了用户直接访问系统的JSP页面,而必须通过Struts2框架来处理请求.
4.
常量配置在5.
2节介绍过使用struts.
properties文件来配置常量,实际上,在struts.
xml中也能配置常量,其配置方式如下代码所示:上面代码配置了常量struts.
i18n.
encoding,指定其值为UTF-8.
struts.
properties文件能配置的常量都可以在struts.
xml文件中用标签来配置.
常量除了通过struts.
xml文件和struts.
properties文件来配置以外,还可以通过web.
xml文件来配置.
下面代码使用了web.
xml来配置常量:struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts.
i18n.
encodingUTF-8上面的代码同样配置了常量struts.
i18n.
encoding,指定其值为UTF-8.
读者需要注意的是,在web.
xml文件中配置常量时,标签必须放在标签下.
通常情况下,struts.
properties、struts.
xml和web.
xml这3个文件都可用来配置常量,但开发时一般的常量配置方式都是在struts.
xml文件中来进行,而不是在struts.
properties文件或是web.
xml文件中.
在Struts2框架中,常量不仅仅存在于struts.
properties﹑struts.
xml和web.
xml这3个文件中,还存在于一些支持Struts2框架的jar包中,如struts-plugin.
xml文件以及struts-default.
xml文件,这些文件中都可以进行常量配置.
通常,Struts2框架加载常量的顺序如下:(1)struts-default.
xml:在struts-core-2.
2.
3.
1.
jar文件中.
(2)struts-plugin.
xml:在struts-Xxx-2.
2.
3.
1.
jar等Struts2插件jar文件中.
第2篇表现层框架Struts技术·142·(3)struts.
xml.
(4)struts.
properties.
(5)web.
xml.
在加载常量的过程中,如果同一个常量出现在多个文件中,则后者会覆盖前者的常量值.
常量的配置方式是多种多样的,但是都需要指定其name和对应的value.
5.
4Struts之Action类文件在前面介绍了Struts框架中的核心配置文件,而在Struts项目开发中和这些核心配置文件同样重要的文件就是Action类文件.
如果说,struts.
xml、struts.
properties和web.
xml文件搭建起了Struts项目的结构,那么Action类文件就实现了具体的业务逻辑处理,Action类文件才是真正实现业务逻辑的文件.
本节将详细介绍Action类文件的相关内容,包括Action类的构造所需要的基类或接口、Action类方法的实现所需访问的数据对象以及异常处理的配置,并通过多个实例来讲解Action类的定义和具体使用方法.
5.
4.
1Action接口和ActionSupport基类在Struts2框架中Action是其主要的业务逻辑处理对象,Struts2框架通过自动调用Action类的方法来实现相应的事件处理.
一般的,每个Action类都定义在一个单独的文件中,实现不同的业务逻辑处理可以通过向该Action类中添加不同的方法来实现.
因此,Action类文件是Struts2框架中非常重要的文件.
下面来介绍Action类的构造所需要的ActionSupport基类以及Action接口.
Struts2框架提供了一个Action接口,该接口定义了Struts2的Action类的实现规范.
publicinterfaceAction{publicstaticfinalStringERROR="error";publicstaticfinalStringSUCCESS="success";publicstaticfinalStringINPUT="input";publicstaticfinalStringLOGIN="login";publicstaticfinalStringNONE="now";publicStringexecute()throwsException;}由Action接口定义可以看到,该接口定义了5个字符串常量和一个execute()方法.
每个Action类都必须包含一个execute()方法,该方法返回一个字符串.
而接口中定义的5个常量用来统一execute()方法返回的值.
实际上,ActionSupport类实现了Action接口,它是一个默认的Aciton实现类,提供了很多默认方法,包括数据校验方法﹑获取国际化信息方法等.
实际应用中,程序员定义的Action类都会继承ActionSupport类而不是实现Action接口,这可以大大简化程序员的编码过程.
值得一提的是,由于自定义的Action类继承了ActionSupport类,因此必须定义一个第5章解密Struts之核心文件·143·变量serialVersionUID.
这是因为ActionSupport类实现了Serializable接口,任何实现Serializable接口的类都必须声明变量serialVersionUID,如下所示:privatestaticfinallongserialVersionUID=1L;5.
4.
2Action与ServletAPIStruts2框架中的Action与Servlet是完全松耦合的,这使得Action类更加方便进行测试.
但对于Web应用来说,ServletAPI是不可忽略的.
在JavaWeb应用中,HttpServletRequest、HttpSession和ServletContext这3个接口是最经常访问的(这3个接口分别对应JSP内置对象中的request、session和application).
在Struts2框架中访问ServletAPI有如下几种方法.
1.
通过ActionContext类访问Strut2框架提供ActionContext类来访问ServletAPI,几个常用方法如下:voidput(Stringkey,Objectvalue):将key-value对放入ActionContext中,模拟ServletAPI中的HttpServletRequest的setAttribute()方法.
Objectget(Objectkey):通过参数key来查找当前ActionContext中的值.
MapgetApplication():返回一个Application级的Map对象.
StaticActionContextgetContext():获得当前线程的ActionContext对象.
MapgetParameters():返回一个包含所有HttpServletRequest参数信息的Map对象.
MapgetSession():返回一个Map类型的HttpSession对象.
voidput(Objectkey,Objectvalue):向当前ActionContext对象中存入名值对信息.
voidsetApplication(Mapapplication):设置Application上下文.
voidsetSession(Mapsession):设置一个Map类型的Session值.
要访问ServletAPI,可以通过如下方式进行访问:ActionContextcontext=ActionContext.
getContext();context.
put("name","tom");context.
getApplication().
put("name","tom");context.
getSession().
put("namme","tom");在上面代码中,通过ActionContext类中的方法调用,分别在request﹑application和session中放入了("name","tom")对.
可以看到,通过ActionContext类,可以非常简单地访问JSP内置对象的属性.
【例5-4】本例示范如何通过ActionContext类来访问ServletAPI.
(1)在Eclipse创建一个JavaWeb项目ActionContextDemo,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中,然后在WEB-INF目录下添加web.
xml文件,并在其中注册过滤器和欢迎页面,代码如下所示:第2篇表现层框架Struts技术·144·struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp(2)在src目录下创建包com.
action,在该包下创建UserAction.
java类文件,代码如下所示:packagecom.
action;importcom.
opensymphony.
xwork2.
ActionContext;importcom.
opensymphony.
xwork2.
ActionSupport;publicclassUserActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;//重载execute()方法publicStringexecute()throwsException{ActionContextcontext=ActionContext.
getContext();//得到ActionContext实例//将(name,"request:tom")到ActionContext中context.
put("name","request:tom");//得到application并将(name,"application:tom")放入context.
getApplication().
put("name","application:tom");//得到session并将(name,"session:tom")放入context.
getSession().
put("name","session:tom");return"hello";//返回hello}}(3)在src目录下创建struts.
xml文件,代码如下所示:/hello.
jsp(4)在WebContent目录下创建index.
jsp和hello.
jsp文件.
index.
jsp文件核心代码:第5章解密Struts之核心文件·145·hellohello.
jsp文件核心代码:${applicationScope.
name}${sessionScope.
name}${requestScope.
name}(5)运行该程序,其结果如图5.
9所示,单击链接后结果如图5.
10所示.
图5.
9例5-4运行结果图5.
10单击链接结果由图5.
10可以看到,在Action中放入的name-value对都被取出来了,这就证明ActionContext能够和ServletAPI打交道.
2.
通过特定接口访问Struts2框架提供了ActionContext类来访问ServletAPI,虽然这种方法可以访问ServletAPI,但是无法直接访问到其实例.
为了在Action中直接访问ServletAPI,可以通过下面几个接口来实现:ServletRequestAware:实现该接口后,可以直接访问HttpServletRequest实例.
ServletResponseAware:实现该接口后,可以直接访问HttpServletResponse实例.
ServletContextAware:实例该接口后,可以直接访问ServletContext实例.
下面举一个ServletContextAware接口的例子,来介绍如何在Action中访问ServletContext实例:publicclassLoginActionimplementsAction,ServletContextAware{privateServletContextcontext;//ServletContext实例//setter方法publicvoidsetServletContext(ServletContextctx){context=ctx;}publicStringexecute()throwsException{context.
setAttribute("user","jim");//将("user","jim")放入ActionContext中第2篇表现层框架Struts技术·146·returnSUCCESS;}}在上面代码中,自定义的LoginAction类实现了Action和ServletContextAware接口.
需要注意的是,LoginAction类定义中必须实现setServletContext()和execute()方法.
通过setServletContext()方法,可以得到ServletContext的实例,这是在调用execute()或其他自定义方法之前就调用的,然后在execute()方法中,就可以访问ServletContext的属性内容.
通过ServletContextAware的例子,读者应该可以猜到其他类似接口的用法.
实际上,如果一个Action实现了ServletRequestAware接口,则必须实现setServletRequest()方法,通过它来访问HttpServletRequest对象;如果一个Aciton实现了ServletResponseAware接口,则必须实现setServletResponse()方法,通过它来访问HttpServletResponse对象.
3.
通过ServletActionContext访问为了直接访问ServletAPI,Struts2框架还提供了ServletActionContext类,该类的几个常用方法如下:HttpServletResponseorg.
apache.
struts2.
ServletActionContext.
getResponse():获得HttpServletResponse对象.
HttpServletRequestorg.
apache.
struts2.
ServletActionContext.
getRequest():获得HttpServletRequest对象.
ServletContextorg.
apache.
struts2.
ServletActionContext.
getServletContext():获得ServletContext对象.
通过ServletActionServlet方法的调用,可以轻松获得相应的JSP内置对象,Action能够更简单方便地访问ServletAPI.
5.
4.
3ModelDriven接口用户在提交HTTP请求时,一般有两种方式,即Get方式和Post方式(当然还有其他方式,但不常用).
Get方式用来获取查询相关信息,即向服务器索取数据,而Post方式则用来更新信息,即向服务器提交数据.
通常情况下,用Get方式向服务器查询信息时,其附带的信息较少,可以使用ServletAPI来一一获取,但当用Post方式提交数据时,往往数据量大,如果仍然用ServletAPI的方式来一一获取数据,代码就显得过于臃肿,而且会降低程序员的工作效率.
这时候,Struts2框架的强大作用就显现出来了.
Struts2框架提供了ModelDriven接口,对于实现了该接口的Action来说,只需定义相应的Model,Struts2框架就会自动将用户提交的HTTP信息赋给相应的Model.
ModelDriven接口的使用方式如以下代码所示:publicclassXxxActionextendsActionSupportimplementsModelDriven{privatestaticfinallongserialVersionUID=1L;privateXXModelx=newXXModel();//创建要使用的对象实例//getter方法,必须实现publicXXModelgetModel(){第5章解密Struts之核心文件·147·returnx;}publicStringexecute()throwsException{returnSUCCESS;}}上面代码中XxxAction类继承了ModelDriven接口,这样用户提交的关于XXModel类的信息,就会直接放入x对象中.
读者需要注意的是XXModel对象必须实例化,且getModel()方法必须重写.
【例5-5】本例示范ModelDriven接口的使用方式.
(1)使用Eclipse创建一个JavaWeb项目ModelDrivenDemo,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中,然后在WEB-INF目录下添加web.
xml文件,并在其中注册过滤器和欢迎页面.
struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp(2)在src目录下创建com.
action包,在该包下创建LoginAction.
java文件.
packagecom.
action;importcom.
model.
UserModel;importcom.
opensymphony.
xwork2.
ActionContext;importcom.
opensymphony.
xwork2.
ActionSupport;importcom.
opensymphony.
xwork2.
ModelDriven;publicclassLoginActionextendsActionSupportimplementsModelDriven{privatestaticfinallongserialVersionUID=1L;privateUserModeluser=newUserModel();//创建UserModel实例//getter方法,必须实现publicUserModelgetModel(){returnuser;}//重载execute方法publicStringexecute()throwsException{第2篇表现层框架Struts技术·148·ActionContextcontext=ActionContext.
getContext();//得到ActionContext实例context.
put("user",user);//将("user",user)放入ActionContext中returnSUCCESS;}}(3)在src目录下创建com.
model包,在该包下创建UserModel.
java文件.
packagecom.
model;publicclassUserModel{privateStringname;//name属性privateStringage;//age属性privateStringaddress;//address属性privateStringtelephone;//telephone属性//name属性的getter和setter方法publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.
name=name;}//age属性的getter和setter方法publicStringgetAge(){returnage;}publicvoidsetAge(Stringage){this.
age=age;}//address属性的getter和setter方法publicStringgetAddress(){returnaddress;}publicvoidsetAddress(Stringaddress){this.
address=address;}//telephone属性的getter和setter方法publicStringgetTelephone(){returntelephone;}publicvoidsetTelephone(Stringtelephone){this.
telephone=telephone;}}(4)在src目录下创建struts.
xml文件.
/success.
jsp第5章解密Struts之核心文件·149·(5)在WebContent目录下创建index.
jsp和success.
jsp文件.
index.
jsp文件核心代码:success.
jsp文件核心代码:(6)运行该程序,其结果如图5.
11所示,输入信息,提交后显示如图5.
12所示的页面.
图5.
11例5-5运行结果图5.
12提交后ModelDriven是一个经常在开发中用到的接口,它大大简化了开发的时间,对于开发者来说,这是一个不可多得的福音.
5.
4.
4异常处理读者可能遇到这样的情况,在开发JavaWeb应用程序的时候,由于程序的开发不太完善,导致用户在使用的过程中出现程序崩溃的情况,结果是在浏览器上面显示一大堆用户无法看懂的东西.
对于商业应用来说,这可能意味着成千上万的损失.
Struts2框架的异常第2篇表现层框架Struts技术·150·处理机制对于这种情况提供了有效的支持.
Struts2框架的异常处理机制是十分成熟的,只需简单的配置就可以实现.
一般情况下,开发者希望实现这样的功能:当处理用户请求时,如果出现了异常,就会转入指定的错误视图资源;如果出现了另一种异常,则系统会转入另一个指定的错误视图资源.
下面的代码就实现了这种功能:publicclassXXXActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;//错误抛出异常publicStringexecute()throwsException{try{returnSUCCESS;}catch(SQLExceptione){e.
printStackTrace();returnERROR;//SQL异常,返回ERROR}catch(InvalidInputExceptione){e.
printStackTrace();returnERROR;//InvalidInput异常,返回ERROR}catch(exception1e1){returnresult1;//自定义异常e1,返回result1}catch(exception2e2){returnresult2;//自定义异常e2,返回result2}}上面的代码虽然可以满足我们提出的要求,但实际上,这种实现方式并不实用.
上述代码是通过try-catch方式来捕获异常的,当异常比较简单、种类较少时,这种方式是可行的.
但在企业级应用中,由于系统的规模常常非常大,如果仍采用try-catch方式来捕获异常,将会降低代码的可维护性.
Struts2框架提供了自己的异常处理机制,只需在struts.
xml文件中配置异常处理即可,而不需要在Action方法中来捕捉异常.
Struts2框架在struts.
xml文件中配置异常通常有两种方式:全局异常配置和局部异常配置.
分别通过标签和标签来配置.
Struts2框架在struts.
xml文件中配置异常的代码如下所示:/Exception.
jsp/SQLException.
jsp第5章解密Struts之核心文件·151·.
.
.
/loginException.
jsp/DataAccess.
jsp.
.
.
上面的struts.
xml文件中配置了3个异常,其中java.
sql.
SQLException和java.
lang.
Exception是全局异常,com.
action.
SecurityException是局部异常.
异常的result属性指的是当Action出现该异常时,系统返回result属性值对应的名称.
需要注意的是,全局异常会对所有的Action起作用,而局部异常只对其所在的Action其作用.
出现异常后,一般会在JSP页面中输出异常信息,通常使用下面两种方式来输出异常信息::输出异常对象信息.
:输出异常堆栈信息.
【例5-6】本例示范Struts2框架异常处理的配置.
(1)在Eclipse中创建一个JavaWeb项目ExceptionDemo,将Struts2框架所需的支持库添加到WEB-INF目录下的lib文件夹中,然后在WEB-INF目录下添加web.
xml文件,并在其中注册过滤器和欢迎页面.
struts2org.
apache.
struts2.
dispatcher.
ng.
filter.
StrutsPrepareAndExecuteFilterstruts2/*index.
jsp(2)在src目录下创建com.
action包,在该包下创建UserAction.
java和SecurityException.
java文件,代码如下所示.
UserAction.
java文件代码如下:packagecom.
action;第2篇表现层框架Struts技术·152·importcom.
opensymphony.
xwork2.
ActionSupport;publicclassUserActionextendsActionSupport{privatestaticfinallongserialVersionUID=1L;privateStringname;//name属性privateStringage;//age属性privateStringtel;//tel属性//name属性的getter、setter方法publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.
name=name;}//age属性的getter、setter方法publicStringgetAge(){returnage;}publicvoidsetAge(Stringage){this.
age=age;}//tel属性的getter、setter方法publicStringgetTel(){returntel;}publicvoidsetTel(Stringtel){this.
tel=tel;}publicStringexecute()throwsException{//根据输入值进行检测是否符合要求if(!
getName().
equals("tom")){thrownewSecurityException("wrongname!
}elseif(!
getAge().
equals("20")){thrownewException("wrongage!
!
!
!
!
");}elseif(!
getTel().
equals("15202208200")){thrownewjava.
sql.
SQLException();}else{returnSUCCESS;}}}SecurityException.
java文件代码如下:packagecom.
action;publicclassSecurityExceptionextendsException{privatestaticfinallongserialVersionUID=1L;//构造方法publicSecurityException(){super();}privateStringmessage;//属性message,用于记录错误消息publicSecurityException(Stringmessage){第5章解密Struts之核心文件·153·this.
message=message;}publicStringgetMessage(){returnmessage;}}(3)在src目录下创建文件struts.
xml.
/Exception.
jsp/SQLException.
jsp/loginException.
jsp/success.
jsp(4)在WebContent目录下创建index.
jsp﹑Exception.
jsp﹑SQLException.
jsp﹑loginException.
jsp和success.
jsp文件,代码如下所示,其中Exception.
jsp﹑SQLException.
jsp和loginException.
jsp文件代码相同.
index.
jsp文件核心代码如下:第2篇表现层框架Struts技术·154·Exception.
jsp、SQLException.
jsp、loginException.
jsp文件核心代码如下:success.
jsp文件核心代码如下:success(5)运行程序,其结果如图5.
13所示,输入信息,若不符合Action中的处理要求,则产生如图5.
14所示的结果,若符合要求,则进入success.
jsp页面.
图5.
13例5-6运行结果图5.
14异常处理结果第5章解密Struts之核心文件·155·5.
5本章小结本章主要介绍了Struts2框架中核心配置文件的作用及其具体配置、Action类文件的具体格式以及访问servletAPI的几种方法.
web.
xml﹑struts.
properties以及struts.
xml三大配置文件,构成了Struts2框架的配置基础,其中web.
xml文件主要是配置初始信息、过滤器等,struts.
properties主要进行常量的配置,而struts.
xml则主要进行Action的配置.
这三个核心配置文件都可以配置常量,如表5.
5所示.
表5.
5三大配置文件的常量配置方式文件代码web.
xmlstruts.
i18n.
encodingUTF-8struts.
propertiesstruts.
i18n.
encoding=UTF-8struts.
xml1.
web.
xmlweb.
xml文件是Struts2框架中的一个重要配置文件,是不可缺少的.
其最重要的就是过滤器的配置,这是其最常用的配置.
2.
struts.
propertiesstruts.
properties文件主要用来配置常量,由于常量可以在web.
xml或struts.
xml中配置,所以该文件有时可以略去不配置.
实际上,Struts2框架按如下顺序来加载常量:struts-default.
xml:在struts-core-2.
2.
3.
1.
jar文件中.
struts-plugin.
xml:在struts-Xxx-2.
2.
3.
1.
jar等Struts2插件jar文件中.
struts.
xml.
struts.
properties.
web.
xml.
上述是Struts2框架搜索常量的顺序,当同一个文件出现多个文件中时,后出现的常量值会覆盖前面的值.
3.
struts.
xmlstruts.
xml文件是Struts2框架中最核心的配置文件,是不可缺少的.
读者应该注意其Action﹑package、result以及通配符等的配置方式.
4.
Action类文件Action类是Struts2框架中很重要的一个组成部分,具体的业务逻辑都是它来进行处理的.
读者须注意在Action中访问ServletAPI的方法以及ModelDriven接口的使用.
棉花云官网棉花云隶属于江西乐网科技有限公司,前身是2014年就运营的2014IDC,专注海外线路已有7年有余,是国内较早从事海外专线的互联网基础服务提供商。公司专注为用户提供低价高性能云计算产品,致力于云计算应用的易用性开发,并引导云计算在国内普及。目前公司研发以及运营云服务基础设施服务平台(IaaS),面向全球客户提供基于云计算的IT解决方案与客户服务(SaaS),拥有丰富的国内BGP、双线高防...
Sharktech 鲨鱼机房商家我们是不是算比较熟悉的,因为有很多的服务商渠道的高防服务器都是拿他们家的机器然后部署高防VPS主机的,不过这几年Sharktech商家有自己直接销售云服务器产品,比如看到有新增公有云主机有促销活动,一般有人可能买回去自己搭建虚拟主机拆分销售的,有的也是自用的。有看到不少网友在分享到鲨鱼机房商家促销活动期间,有赠送开通公有云主机$50,可以购买最低配置的,$49/月的...
台湾云服务器去哪里买?国内有没有哪里的台湾云服务器这块做的比较好的?有很多用户想用台湾云服务器,那么判断哪家台湾云服务器好,不是按照最便宜或最贵的选择,而是根据您的实际使用目的选择服务器,只有最适合您的才是最好的。总体而言,台湾云服务器的稳定性确实要好于大陆。今天,云服务器网(yuntue.com)小编来介绍一下台湾云服务器哪里买和一年需要多少钱!一、UCloud台湾云服务器UCloud上市云商,...
403forbidden怎么解决为你推荐
netlife熊猫烧香是怎么制作的lunwenjiance我写的论文,检测相似度是21.63%,删掉参考文献后就只有6.3%,这是为什么?陈嘉垣大家觉得陈嘉桓漂亮还是钟嘉欣漂亮?陈嘉垣反黑阿欣是谁演的 扮演者介绍百花百游“百花竟放贺阳春 万物从今尽转新 末数莫言穷运至 不知否极泰来临”是什么意思啊?seo优化工具想找一个效果好的SEO优化软件使用,在网上找了几款不知道哪款好,想请大家帮忙出主意,用浙江哪款软件效果好haole16.com玛丽外宿中16全集在线观看 玛丽外宿中16qvod快播高清下载www.zjs.com.cn怎么查询我的平安信用卡寄送情况www.zjs.com.cn中通快递投诉网站网址是什么?bbs2.99nets.com这个"风情东南亚"网站有78kg.cn做网址又用bbs.风情东南亚.cn那么多此一举啊!
cn域名注册 过期已备案域名 主机优惠码 罗马假日广场 5折 优key gitcafe win8升级win10正式版 国外免费空间 mysql主机 电信虚拟主机 免费外链相册 dnspod cxz 新加坡空间 东莞主机托管 服务器防火墙 贵阳电信 lamp什么意思 域名转入 更多