Struts2之拦截器
一.Struts2有一核心技术是拦截器,英文名为Interceptor。拦截器本来是WebWork框架中一个很好的支持国际化、校验、类型转换的工具。现在WebWork和Struts合并成Struts2之后,理所当然也成为Struts2的一部分。
1.拦截器本身也是一个普通的Java对象,它的功能是动态拦截Action调用,在Action执行前后执行拦截器本身提供的各种各样的Web项目需求。当然也可以阻止Action的执行,同时也可以提取Action中可以复用的部分。
2.在Struts2中还有个拦截器栈的概念,其实它就是拦截器的一个集合。它把多个拦截器集合起来,按照在栈中配置的顺序执行,特别是针对Action可以拦截相应的方法或者字段。
二.拦截器在Struts2中的缺省应用与配置:
1.在Web项目中,客户先在视图界面提交一个HTTP请求,在Struts2的ServletDispatcher接收请求,Struts2会查找struts.xml配置文件。根据struts.xml配置文件中定义的拦截器配置,会去调用拦截器。如果配置了拦截器栈,则根据拦截器在拦截器栈中的前后顺序,一一进行调用。而Struts2自带的源代码中也提供了缺省的拦截器配置。
(1).在我们下载的Struts2的包里中,解压后struts-2.3.20文件夹底下,在src文件夹中包含了Struts2的所有底层实现源代码,我们可到自己安装的Struts2的文件路径下找到src\core\src\main\resources\中,其中有个名为struts-default.xml文件。它是Struts2自定义的配置文件,其中有关拦截器的配置代码便是拦截器在Struts2中的缺省应用。
如果要在MyEclipse工具中查看,可以打开Struts2项目中的Web App Libraries下的 struts2-core-2.3.20.jar下的struts-default.xml文件。
(2).接下来附上struts-default.xml文件中有关拦截器的配置代码,如下:
<interceptors><interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/><interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/><interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/><interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/><interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/><interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/><interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" /><interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" /><interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" /><interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/><interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/><interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/><interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/><interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/><interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/><interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/><interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/><interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/><interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/><interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/><interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/><interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/><interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/><interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/><interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/><interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/><interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/><interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" /><interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" /><interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" /><interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" /><interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" /><interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" /><interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" /><interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" /><!-- Basic stack --><interceptor-stack name="basicStack"><interceptor-ref name="exception"/><interceptor-ref name="servletConfig"/><interceptor-ref name="prepare"/><interceptor-ref name="checkbox"/><interceptor-ref name="datetime"/><interceptor-ref name="multiselect"/><interceptor-ref name="actionMappingParams"/><interceptor-ref name="params"><param name="excludeParams">^action:.*,^method:.*</param></interceptor-ref><interceptor-ref name="conversionError"/><interceptor-ref name="deprecation"/></interceptor-stack><!-- Sample validation and workflow stack --><interceptor-stack name="validationWorkflowStack"><interceptor-ref name="basicStack"/><interceptor-ref name="validation"/><interceptor-ref name="workflow"/></interceptor-stack><!-- Sample file upload stack --><interceptor-stack name="fileUploadStack"><interceptor-ref name="fileUpload"/><interceptor-ref name="basicStack"/></interceptor-stack><!-- Sample model-driven stack --><interceptor-stack name="modelDrivenStack"><interceptor-ref name="modelDriven"/><interceptor-ref name="basicStack"/></interceptor-stack><!-- Sample action chaining stack --><interceptor-stack name="chainStack"><interceptor-ref name="chain"/><interceptor-ref name="basicStack"/></interceptor-stack><!-- Sample i18n stack --><interceptor-stack name="i18nStack"><interceptor-ref name="i18n"/><interceptor-ref name="basicStack"/></interceptor-stack><!-- An example of the paramsPrepareParams trick. This stackis exactly the same as the defaultStack, except that itincludes one extra interceptor before the prepare interceptor:the params interceptor.This is useful for when you wish to apply parameters directlyto an object that you wish to load externally (such as a DAOor database or service layer), but can't load that objectuntil at least the ID parameter has been loaded. By loadingthe parameters twice, you can retrieve the object in theprepare() method, allowing the second params interceptor toapply the values on the object. --><interceptor-stack name="paramsPrepareParamsStack"><interceptor-ref name="exception"/><interceptor-ref name="alias"/><interceptor-ref name="i18n"/><interceptor-ref name="checkbox"/><interceptor-ref name="datetime"/><interceptor-ref name="multiselect"/><interceptor-ref name="params"><param name="excludeParams">^action:.*,^method:.*</param></interceptor-ref><interceptor-ref name="servletConfig"/><interceptor-ref name="prepare"/><interceptor-ref name="chain"/><interceptor-ref name="modelDriven"/><interceptor-ref name="fileUpload"/><interceptor-ref name="staticParams"/><interceptor-ref name="actionMappingParams"/><interceptor-ref name="params"><param name="excludeParams">^action:.*,^method:.*</param></interceptor-ref><interceptor-ref name="conversionError"/><interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref></interceptor-stack><!-- A complete stack with all the common interceptors in place.Generally, this stack should be the one you use, though itmay do more than you need. Also, the ordering can beswitched around (ex: if you wish to have your servlet-relatedobjects applied before prepare() is called, you'd need to moveservletConfig interceptor up.This stack also excludes from the normal validation and workflowthe method names input, back, and cancel. These typically areassociated with requests that should not be validated.--><interceptor-stack name="defaultStack"><interceptor-ref name="exception"/><interceptor-ref name="alias"/><interceptor-ref name="servletConfig"/><interceptor-ref name="i18n"/><interceptor-ref name="prepare"/><interceptor-ref name="chain"/><interceptor-ref name="scopedModelDriven"/><interceptor-ref name="modelDriven"/><interceptor-ref name="fileUpload"/><interceptor-ref name="checkbox"/><interceptor-ref name="datetime"/><interceptor-ref name="multiselect"/><interceptor-ref name="staticParams"/><interceptor-ref name="actionMappingParams"/><interceptor-ref name="params"><param name="excludeParams">^action:.*,^method:.*</param></interceptor-ref><interceptor-ref name="conversionError"/><interceptor-ref name="validation"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="workflow"><param name="excludeMethods">input,back,cancel,browse</param></interceptor-ref><interceptor-ref name="debugging"/><interceptor-ref name="deprecation"/></interceptor-stack><!-- The completeStack is here for backwards compatibility forapplications that still refer to the defaultStack by theold name --><interceptor-stack name="completeStack"><interceptor-ref name="defaultStack"/></interceptor-stack><!-- Sample execute and wait stack.Note: execAndWait should always be the *last* interceptor. --><interceptor-stack name="executeAndWaitStack"><interceptor-ref name="execAndWait"><param name="excludeMethods">input,back,cancel</param></interceptor-ref><interceptor-ref name="defaultStack"/><interceptor-ref name="execAndWait"><param name="excludeMethods">input,back,cancel</param></interceptor-ref></interceptor-stack></interceptors><default-interceptor-ref name="defaultStack"/><default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
(3).接下来来解释上图中的struts-default.xml文件的代码:
— 在xml配置文件中配置拦截器和拦截器栈都是以“<interceptors>”开头,以“</interceptors>”结尾。
— 配置拦截器的格式如上面代码所示以“<interceptor/>”格式显示,其中有两个属性:name是拦截器的名字,另一个class是对应的类路径,因为前面说过拦截器也是一个普通的Java对象。
— 拦截器栈的格式是以“<interceptor-stack>”开头,以“</interceptor-stack>”结尾。其中属性name是拦截器栈的名字。在“<interceptor-stack>”和“</interceptor-stack>”之间可以设置拦截器。如struts-default.xml文件中的代码所示格式为“<interceptor-ref/>”,其中name属性也是拦截器名字。如果系统运行拦截器栈,都是按照拦截器栈中定义的拦截器先后顺序执行拦截器。
注:1.请大家仔细查看那个基础栈的配置,即basicStack这个栈,其中配置的拦截器都是在struts-default.xml文件中定义的拦截器。在struts-default.xml文件中的defaultStack栈里的拦截器配置是我们经常用的。
注:2.拦截器栈中不单单可以配置拦截器,它甚至还可以配置拦截器栈。比如在struts-default.xml文件代码中的“validationWorkflowStack”拦截器栈中就配置了“basicStack”拦截器栈。这样的话,配置的子拦截器栈中的拦截器也会被执行。这就类似于父集合和子集合的概念。
(4).针对struts-default.xml文件中各个拦截器配置一一做介绍,因为如果使用Struts2在Web项目开发中,这些拦截器默认缺省的会被执行的。因此,了解一下Struts2底层的拦截器到底实现什么功能对开发人员来说是很有帮助的。
2.下面对Struts2中底层的拦截器进行介绍,即了解一下对struts-default.xml文件中的拦截器:
1.alias:对于HTTP请求包含的参数设置别名。
2.autowiring:将某些JavaBean实例自动绑定到其他Bean对应的属性中。有点类似Spring的自动绑定。
3.chain:在Web项目开发中,以前使用Struts开发时候经常碰到两个Action互相传递参数或属性的情况。该拦截器就是让前一个Action的参数可以在现有Action中使用。
4.conversionError:从ActionContext中将转换类型时候发生的错误添加到Action的值域错误中,在校验时候经常被使用到来显示类型转换错误的信息。
5.cookie:从Struts2.0.7版本开始,可以把cookie注入Action中可设置的名字或值中。
6.createSession:自动创建一个HTTP的Session,尤其是对需要HTTP的Session的拦截器特别有用,如下面要介绍的TokenInterceptor。
7.debugging:用来对在视图间传递的数据进行调试。
8.execAndWait:不显式执行Action,在视图上显示给用户的是一个正在等待的页面,但是Action其实是在背后正在执行着的。该拦截器尤其是在进度条开发的时候特别有用。
9.exception:将异常和Action返回的result相映射。
10.fileUpload:支持文件上传功能的拦截器。
11.i18n:支持国际化的拦截器。
12.logger:拥有日志功能的拦截器。
13.modelDriven:Action执行该拦截器的时候,可以将getModel方法得到的result值放入值栈中。
14.scopedModelDriven:执行该拦截器时,它可以从一个scope范围检索和存储model值,通过调用setModel方法去设置model值。
15.params:将HTTP请求中包含的参数值设置到Action中。
16.prepare:假如Action继承了Preparable接口,则会调用prepare方法。
17.staticParams:对于在struts.xml文件中Action中设置的参数设置到对应的Action中。
18.scope:在session或者application范围中设置Action的状态。
19.servletConfig:该拦截器提供访问包含HttpServletResquest和HttpServletResponse对象的Map的方法。
20.timer:输出Action的执行时间。
21.token:避免重复提交的校验拦截器。
22.tokenSession:和token拦截器类似,但它还能存储提交的数据到Session里。
23.validation:运行在action-validation.xml文件中定义的校验规则。其中action-validation.xml是对一个Action类的校验。
24.workflow:在Action中调用validate校验方法。如果Action有错误则返回到input视图。
25.store:执行校验功能时,该拦截器提供存储和检索Action的所有错误和正确信息的功能。
26.checkbox:视图中如果有checkbox存在的情况,该拦截器自动将unchecked的checkbox当作一个参数(通常值为false)记录下来。这样可以用一个隐藏的表单值来记录所有未提交的checkbox,而且缺省unchecked的checkbox值是布尔类型的,如果视图中checkbox的值设置的不是布尔类型,它就会被覆盖成布尔类型的值。
27.profiling:通过参数来激活或不激活分析检测功能,前提是Web项目是在开发者模式下。(涉及到调试和性能检验时使用)
28.roles:进行权限配置的拦截器,如果登录用户拥有相应权限才去执行某一特定的Action。
package com.action;import com.opensymphony.xwork2.ActionSupport;public class TimerInterceptorAction extends ActionSupport {public String execute() throws Exception{Thread.sleep(5000);//让线程睡眠5000毫秒,即睡眠5秒return SUCCESS;}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.enable.DynamicMethodInvocation" value="true"></constant><constant name="struts.devMode" value="true"></constant><package name="default" namespace="/" extends="struts-default"><action name="timeTest" class="com.action.TimerInterceptorAction"><interceptor-ref name="timer"/><result>/index.jsp</result></action></package>
</struts>
<interceptors><interceptor name="replace" class="com.gk.interceptor.MyInterceptor"></interceptor><interceptor name="replace1" class="com.gk.interceptor.MyInterceptor1"></interceptor>
</interceptors>
<action name="public" class="com.gk.action.PublicAction"><result name="success">/success.jsp</result><result name="login">/success.jsp</result><interceptor-ref name="defaultStack"></interceptor-ref><interceptor-ref name="replace"></interceptor-ref><interceptor-ref name="replace1"></interceptor-ref>
</action>
4.接下来附上一个例子,新建一个Struts2项目,项目名为InterceptorTest,此项目用来演示拦截用户评论的脏话,如今社会,网民过多,有些没素质的人往往用一些粗俗的话语来发表言语,所以有必要要拦截一些脏话,像英雄联盟这个游戏,就把lol和送,以及fuck给屏蔽掉了,发送过去会把这些字改变为*和#等,项目结构图如下:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>My JSP 'news.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--></head><body><center>发表评论<s:form action="public" namespace="/" method="post"><s:textfield name="title" label="标题"/><s:textarea name="content" cols="30" rows="5" label="内容"/><s:submit value="评论"></s:submit></s:form></center></body>
</html>
package com.gk.action;import com.opensymphony.xwork2.ActionSupport;public class PublicAction extends ActionSupport {private String title;private String content;public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public String execute(){return SUCCESS;}}
(3).接着新建两个自定义的拦截器类,放在com.gk.interceptor包下,分别为MyInterceptor和MyIntercepter1类,都继承了AbstractInterceptor类,代码分别如下:
package com.gk.interceptor;import com.gk.action.PublicAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class MyInterceptor extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation invocation) throws Exception {PublicAction action=(PublicAction) invocation.getAction();//取得Action的实例String content=action.getContent();//获得action中的content内容,即news.jsp文件表单里的输入的内容//如果输入的内容包含叼字的话if(content.contains("叼")){content=content.replaceAll("叼", "*");//把内容里所有有叼字的全部替换为*号action.setContent(content);//在重新设置内容return invocation.invoke();//返回拦截后结果码}else{return action.LOGIN;//如果没有叼字,返回结果码}}}
MyInterceptor1.java文件的代码如下:
package com.gk.interceptor;import com.gk.action.PublicAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;public class MyInterceptor1 extends AbstractInterceptor {@Overridepublic String intercept(ActionInvocation invocation) throws Exception {PublicAction action=(PublicAction) invocation.getAction();//取得Action的实例String title=action.getTitle();//获得action中的title内容,即news.jsp页面的表单里的输入标题//如果输入的标题有死字的if(title.contains("死")){title=title.replaceAll("死", "*");//把死字全部替换为*action.setTitle(title);//再重新设置标题内容return invocation.invoke();//返回拦截后结果码}return action.LOGIN;//如果没有死字,返回结果码}}
(4).最后,配置struts.xml文件,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts><constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<constant name="struts.devMode" value="true"></constant><package name="interceptor" namespace="/" extends="struts-default"><interceptors><interceptor name="replace" class="com.gk.interceptor.MyInterceptor"></interceptor><interceptor name="replace1" class="com.gk.interceptor.MyInterceptor1"></interceptor></interceptors><action name="public" class="com.gk.action.PublicAction"><result name="success">/success.jsp</result><result name="login">/success.jsp</result><interceptor-ref name="defaultStack"></interceptor-ref><interceptor-ref name="replace"></interceptor-ref><interceptor-ref name="replace1"></interceptor-ref></action></package>
</struts>
注:这里要注意要在action里必须加上 <interceptor-ref name="defaultStack"></interceptor-ref> 这行代码,否则会报错。
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>My JSP 'success.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--></head><body>标题为:<s:property value="title"/><br/>评论内容为:<s:property value="content"/></body>
</html>
(6).部署此项目到Tomcat服务器上,开启Tomcat服务器,效果如下:
Struts2之拦截器相关推荐
- struts2自定义拦截器并配置拦截器使其生效
首先编写一个struts2的拦截器,要继承 MethodFilterInterceptor 并获取其中的方法 package star.july.d_interceptor;import com.op ...
- (转)Struts2的拦截器
http://blog.csdn.net/yerenyuan_pku/article/details/68648101 Struts2的拦截器 拦截器的概述 拦截器,在AOP(Aspect-Orien ...
- Struts2之拦截器篇
拦截器是Struts2框架的核心和基础,Struts2绝大多数功能都是通过拦截器来完成的,当StrutsPrepareAndExecuteFilter拦截到用户请求后,大量拦截器会对该请求进行处理,然 ...
- Struts2【拦截器】就是这么简单
2019独角兽企业重金招聘Python工程师标准>>> 什么是拦截器 拦截器Interceptor.....拦截器是Struts的概念,它与过滤器是类似的...可以近似于看作是过滤器 ...
- struts2 18拦截器详解(五)
I18nInterceptor 该拦截器处理defaultStack第四的位置,是用来方便国际化的,如果说我们的一个Web项目要支持国际化的话,通常的做法是给定一个下拉框列出所支持的语言,当用户选择了 ...
- Struts2自定义拦截器实例—登陆权限验证
版本:struts2.1.6 此实例实现功能:用户需要指定用户名登陆,登陆成功进入相应页面执行操作,否则返回到登陆页面进行登陆,当直接访问操作页面(登陆后才能访问的页面)时则不允许,须返回登陆页面. ...
- dwz ajax session超时跳转登录页(struts2自定义拦截器)
1.定义struts2拦截器(网上例子很多) 代码如下: package rt.intercepter;import java.util.Map;import javax.servlet.http.H ...
- Struts2 自定义拦截器(方法拦截器)
转自:http://05061107cm.iteye.com/blog/365504 struts2系统自带了很多拦截器,有时需要我们自己定义,一般有两种方式: 一.实现Interceptor接口 J ...
- struts2中拦截器的使用
拦截器的使用 实现AOP 转自http://www.cnblogs.com/fmricky/archive/2010/05/24/1742514.html 1.什么是拦截器(Interceptor) ...
- Struts2 自定义拦截器(easy example)
要自定义拦截器需要实现com.opensymphony.xwork2.interceptor.Interceptor接口: 新建一个MyIntercept package com.action;imp ...
最新文章
- 对称加密DES和TripleDES
- 将ssm项目和普通java项目打包
- MongoDB文档对象字段属性合并的2种转换方法
- BP神经网络 语音信号分类
- 优惠券卡包应用数据库字段设计/系统架构设计/缓存层设计方案
- 为什么S/4HANA的销售订单创建会触发生产订单的创建 1
- java 正则提取及替换字符串
- hexo github搭建博客常用的命令
- 编程基础C——常量,变量,运算符个人总结
- WPF 中的Width 与 ActualWidth
- Java 第五章 类的设计与包
- Android的手机震动
- php 合计,表格怎么合计总数
- 7Zip下载-适用 Windows 解压软件
- xshell查看hdfs文件目录路径_hdfs的shell操作
- 人的成熟不是年龄,而是懂得了放弃。Python_China的博客
- HDU 6070 线段树
- UE4 本地化多语言
- CSS 特殊性(Specificity)
- linux命令--netstat