今天項目遇到一個問題,我們項目用戶驗證和權限驗證的信息(licence)是在http頭中設置的,百度了一下,只有ajax才能設置頭信息,form表單是無法設置的,但是我突然想起springMVC關於form表單解決put、delete提交方式的問題,我靈機一動,於是模仿springMVC實現了設置自定義header的功能。
起源
項目使用的是SSM框架,廢話不多說,我們先看springMVC對於form表單提交put、delete請求問題的解決方案,springMVC是使用了一個過濾器,使之用用戶只需在form表單增加一個隱藏域_method即可,比如下面這樣:
- <form id="fm" method="post" >
- <input type="hidden" name="_method" value="put"/>
- <input type="hidden" name="_header" value="${licence }"/>
- <div class="fitem">
- <label>uNum:</label>
- <input name="uNum" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>uPass:</label>
- <input name="uPass" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>uName:</label>
- <input name="uName" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>csId:</label>
- <input name="csId" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>uJob:</label>
- <input name="uJob" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>uStartTime:</label>
- <input name="uStartTime" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>rId:</label>
- <input name="rId" class="easyui-validatebox" required="true">
- </div>
- <div class="fitem">
- <label>uMail:</label>
- <input name="uMail" class="easyui-validatebox" validType="email" required="true">
- </div>
- <div class="fitem">
- <label>uState:</label>
- <input name="uState" class="easyui-validatebox" required="true">
- </div>
- </form>
_method里的值就是你要提交方式,具體情況大家自己百度我就細說了。
實現
springmvc在web.xml中配置是這樣的
- <filter>
- <filter-name>httpMethodFilter</filter-name>
- <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>httpMethodFilter</filter-name>
- <servlet-name>SpringMVC</servlet-name>
- </filter-mapping>
然后我們來看springMVC的源碼:
- /*
- * Copyright 2002-2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.springframework.web.filter;
- import java.io.IOException;
- import java.util.Locale;
- import javax.servlet.FilterChain;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.util.Assert;
- import org.springframework.util.StringUtils;
- /**
- * {@link javax.servlet.Filter} that converts posted method parameters into HTTP methods,
- * retrievable via {@link HttpServletRequest#getMethod()}. Since browsers currently only
- * support GET and POST, a common technique - used by the Prototype library, for instance -
- * is to use a normal POST with an additional hidden form field ({@code _method})
- * to pass the "real" HTTP method along. This filter reads that parameter and changes
- * the {@link HttpServletRequestWrapper#getMethod()} return value accordingly.
- *
- * <p>The name of the request parameter defaults to {@code _method}, but can be
- * adapted via the {@link #setMethodParam(String) methodParam} property.
- *
- * <p><b>NOTE: This filter needs to run after multipart processing in case of a multipart
- * POST request, due to its inherent need for checking a POST body parameter.</b>
- * So typically, put a Spring {@link org.springframework.web.multipart.support.MultipartFilter}
- * <i>before</i> this HiddenHttpMethodFilter in your {@code web.xml} filter chain.
- *
- * @author Arjen Poutsma
- * @since 3.0
- */
- public class HiddenHttpMethodFilter extends OncePerRequestFilter {
- /** Default method parameter: {@code _method} */
- public static final String DEFAULT_METHOD_PARAM = "_method";
- private String methodParam = DEFAULT_METHOD_PARAM;
- /**
- * Set the parameter name to look for HTTP methods.
- * @see #DEFAULT_METHOD_PARAM
- */
- public void setMethodParam(String methodParam) {
- Assert.hasText(methodParam, "'methodParam' must not be empty");
- this.methodParam = methodParam;
- }
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- String paramValue = request.getParameter(this.methodParam);
- if ("POST".equals(request.getMethod()) && StringUtils.hasLength(paramValue)) {
- String method = paramValue.toUpperCase(Locale.ENGLISH);
- HttpServletRequest wrapper = new HttpMethodRequestWrapper(request, method);
- filterChain.doFilter(wrapper, response);
- }
- else {
- filterChain.doFilter(request, response);
- }
- }
- /**
- * Simple {@link HttpServletRequest} wrapper that returns the supplied method for
- * {@link HttpServletRequest#getMethod()}.
- */
- private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper {
- private final String method;
- public HttpMethodRequestWrapper(HttpServletRequest request, String method) {
- super(request);
- this.method = method;
- }
- @Override
- public String getMethod() {
- return this.method;
- }
- }
- }
重點我們來看他寫的HttpMethodRequestWrapper這個內部類,這個類繼承HttpServletRequestWrapper,而HttpServletRequestWrapper我進去看了下都是調用更上層的方法自己並沒有做什么事情,再往上我就沒去看了。我理解的他的原理是:request在得到method時時使用getMethod方法的,所以他重寫了getMethod方法,從而可以把_method的值當做method。
那么既然這樣,我也可以把_header的值當做header啊,而request獲取header的方法是public String getHeader(String name),所以我就寫了下面這樣的過濾器:
- package com.zs.tools;
- import java.io.IOException;
- import javax.servlet.FilterChain;
- import javax.servlet.ServletException;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletRequestWrapper;
- import javax.servlet.http.HttpServletResponse;
- import org.springframework.web.filter.HiddenHttpMethodFilter;
- /**
- * 張順,2017-2-28
- * 處理form表單頭的過濾器,
- * 如果表單有_header字段,可以自動將該字段轉為request的header頭信息(增加一條頭)
- * @author it023
- */
- public class MyHiddenHttpMethodFilter extends HiddenHttpMethodFilter{
- @Override
- protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException {
- String header=request.getParameter("_header");
- if (header!=null && !header.trim().equals("")) {
- HttpServletRequest wrapper = new HttpHeaderRequestWrapper(request,header);
- super.doFilterInternal(wrapper, response, filterChain);
- }else {
- super.doFilterInternal(request, response, filterChain);
- }
- }
- private static class HttpHeaderRequestWrapper extends HttpServletRequestWrapper{
- private final String header;
- public HttpHeaderRequestWrapper(HttpServletRequest request,String licence) {
- super(request);
- this.header=licence;
- }
- @Override
- public String getHeader(String name) {
- if (name!=null &&
- name.equals("licence") &&
- super.getHeader("licence")==null) {
- return header;
- }else {
- return super.getHeader(name);
- }
- }
- }
- }
然后,在web.xml中配置一下,我是放在HiddenHttpMethodFilter前面的。
- <filter>
- <filter-name>httpHeaderFilter</filter-name>
- <filter-class>com.zs.tools.MyHiddenHttpMethodFilter</filter-class>
- </filter>
- <filter-mapping>
- <filter-name>httpHeaderFilter</filter-name>
- <servlet-name>SpringMVC</servlet-name>
- </filter-mapping>
結果
結果很成功,具體的代碼我不想貼了,請看日志,這一條表示獲取到http頭的licence(不要在意licence為什么這么簡單,那是因為這是測試數據)。
轉自http://blog.csdn.net/fe123rarwa14235pp/article/details/58607296