Strut2는 AJAX 호출인지 확인
1. AJAX 및 기존 형식
사실 둘 다 일반적으로 HTTP를 통한 POST 요청입니다. 차이점은 브라우저가 양식을 제출한 후 서버가 완전한 HTML 페이지를 반환할 것으로 예상한다는 것입니다. AJAX 호출은 XMLHttpRequest 객체에 의해 실행됩니다(브라우저마다 다를 수 있음). 특히 JSON, XML 등에 대한 요구 사항은 없습니다. 브라우저로 복귀한 후 어떻게 사용하는지도 JS 스크립트 자체에 의해 결정됩니다.
2. 요청이 AJAX인지 여부
그럼 서버측에서는 HTTP 요청이 AJAX 호출인지 어떻게 확인하나요? 이를 위해서는 HTTP 헤더를 살펴봐야 합니다.
헤더의 x-request-with로 판단할 수 있습니다. 브라우저마다 AJAX 요청을 다른 객체로 보내지만, jQuery를 사용하여 AJAX 요청을 보내는 경우 jQuery가 내부적으로 ajax를 구현할 때 식별자가 추가됩니다. jQuery 소스 코드는 다음과 같습니다. xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
따라서 프로젝트의 프런트 엔드 페이지에서 jQuery를 통해 AJAX 요청을 보내는 경우 이 판단은 안전합니다.
다음은 HTTP 요청이 전달하는 헤더 정보입니다.
일반양식 제출
===MimeHeaders === accept = */* referer =http://localhost:8080/user2/toQueryPage.action accept-language = zh-CN user-agent = Mozilla/4.0 (compatible; MSIE8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C;.NET4.0E) accept-encoding = gzip, deflate host = localhost:8080 connection = Keep-Alive cache-control = no-cache
AJAX 호출(IE)
===MimeHeaders === x-requested-with = XMLHttpRequest accept-language = zh-cn referer =http://localhost:8080/user2/toQueryPage.action accept = application/json, text/javascript,*/*; q=0.01 content-type =application/x-www-form-urlencoded accept-encoding = gzip, deflate user-agent = Mozilla/4.0 (compatible; MSIE8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.3; .NET4.0C;.NET4.0E) host = localhost:8080 content-length = 57 connection = Keep-Alive cache-control = no-cache
3. Action의 HTTP 요청 헤더
Action 클래스에서 ServletRequestAware 인터페이스를 통해 HttpServletRequest 객체를 얻은 후, getHeader 메소드를 통해 원하는 헤더 정보를 얻습니다.
public abstract class BaseAction <ParamVo extends BaseParamVo, ResultVo extends BaseResultVo> extends ActionSupport implements ServletRequestAware { private static final String AJAX_RESULT_NAME = "ajaxResult"; private static final String XHR_OBJECT_NAME = "XMLHttpRequest"; private static final String HEADER_REQUEST_WITH = "x-requested-with"; /** * Request对象,用来判断请求是否是AJAX调用 */ private HttpServletRequest request; private ParamVo paramVo; private ResultVo resultVo; @Override public String execute() { String resultPage = SUCCESS; try { resultVo = doExecute(paramVo); } catch (BaseException e) { resultPage = ERROR; } if (XHR_OBJECT_NAME.equals(request.getHeader(HEADER_REQUEST_WITH))) { resultPage = AJAX_RESULT_NAME; } return resultPage; } }
Struts2 Performance Tuning Interceptor
직장에서 몇 가지 작은 요구 사항을 구현해야 할 경우 먼저 간단한 설문 조사를 수행하는 것이 좋습니다. 사용 중인 오픈 소스 프레임워크에 이미 필요한 기능이 있는 경우에는 바퀴를 다시 만들 필요가 없습니다.
Struts2 프레임워크에 이 기능이 있는지 조사하는 방법을 알아보기 위해 성능 테스트를 예로 들어 보겠습니다.
1. struts-default.xml
Struts2의 핵심 기능 중 다수가 내부 인터셉터를 기반으로 구현되어 있으므로 먼저 성능 튜닝 관련 차단 장치가 있는지 확인해야 합니다. 이를 위해서는 strut2-core-2.3.1.2.jar의 기본 구성 파일 struts-default.xml을 확인해야 합니다.
<span style="white-space:pre"> </span><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="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"/> <interceptornameinterceptorname="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="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" />
Struts2에는 보물 상자처럼 인터셉터가 많이 내장되어 있으므로 프로파일링이 아마도 우리의 요구 사항을 충족하는 인터셉터임을 알 수 있습니다. 이제 소스코드를 확인해 보세요.
2. ProfilingActivationInterceptor
org.apache.struts2.interceptor.ProfilingActivationInterceptor.java
public class ProfilingActivationInterceptor extendsAbstractInterceptor { private String profilingKey = "profiling"; private boolean devMode; @Inject(StrutsConstants.STRUTS_DEVMODE) public void setDevMode(String mode) { this.devMode = "true".equals(mode); } @Override public String intercept(ActionInvocationinvocation) throws Exception { if (devMode) { Object val =invocation.getInvocationContext().getParameters().get(profilingKey); if (val != null) { String sval = (val instanceof String ?(String)val : ((String[])val)[0]); boolean enable = "yes".equalsIgnoreCase(sval)|| "true".equalsIgnoreCase(sval); UtilTimerStack.setActive(enable); invocation.getInvocationContext().getParameters().remove(profilingKey); } } return invocation.invoke(); } }
브라우저가 보낸 HTTP 요청 매개변수에 profiling=true 또는 yes가 포함되어 있는 한 성능 인터셉터는 타이머 도구 클래스를 열고 작업의 실행 시간을 인쇄한다는 것을 소스 코드에서 볼 수 있습니다.
<package name="ajax-default" extends="velocity-default"> <result-types> <result-type name="json" class="org.apache.struts2.json.JSONResult"/> </result-types> <interceptors> <interceptor-stacknameinterceptor-stackname="ajaxInterceptorStack"> <interceptor-refnameinterceptor-refname="defaultStack" /> <interceptor-ref name="profiling"/> </interceptor-stack> </interceptors> <default-interceptor-refnamedefault-interceptor-refname="ajaxInterceptorStack" /> <global-results> <result name="comAjaxResult" type="json"> <param name="excludeNullProperties">true</param> <param name="root">result</param> <param name="ignoreHierarchy">false</param> </result> </global-results> </package>4. userview.js이제 AJAX 호출 매개변수를 수정하고 프로파일링 매개변수를 추가하여 성능 튜닝을 시작할 수 있습니다.
function searchAllUser(){ jQuery.ajax({ type:"post", url: "searchAllUser.action", processData:true, dataType:'json', data:jQuery("#userQueryForm").serialize() + "&profiling=yes", success:function(data) { if (data.status == 1) { alert("创建成功"); generateTableFromJson("result", data.resultRows); } else { alert("创建失败"); } } }); }
5. 최종 효과
인쇄된 결과는 다음과 같습니다. 총 실행 시간 외에 Action 메서드의 실행 시간과 Result 렌더링 시간도 별도로 나열됩니다.