使用过滤器间接实现form表单设置自定义http头(header)功能

今天项目遇到一个问题,我们项目用户验证和权限验证的信息(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为什么这么简单,那是因为这是测试数据)。








好的,我来回答你的问题。 1. 实现全局编码过滤器功能实现全局编码过滤器功能,可以在 web.xml 文件中配置一个字符编码过滤器。具体步骤如下: - 在 web.xml 文件中添加以下代码: ``` <filter> <filter-name>encodingFilter</filter-name> <filter-class>com.example.EncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> ``` - 创建一个 EncodingFilter 类,代码如下: ``` public class EncodingFilter implements Filter { private String encoding; @Override public void init(FilterConfig filterConfig) throws ServletException { encoding = filterConfig.getInitParameter("encoding"); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding(encoding); response.setCharacterEncoding(encoding); chain.doFilter(request, response); } @Override public void destroy() { encoding = null; } } ``` 2. 实现登录过滤器功能实现登录过滤器功能,可以在 web.xml 文件中配置一个登录过滤器。具体步骤如下: - 在 web.xml 文件中添加以下代码: ``` <filter> <filter-name>LoginFilter</filter-name> <filter-class>com.example.LoginFilter</filter-class> </filter> <filter-mapping> <filter-name>LoginFilter</filter-name> <url-pattern>/admin/*</url-pattern> </filter-mapping> ``` - 创建一个 LoginFilter 类,代码如下: ``` public class LoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse resp = (HttpServletResponse) response; HttpSession session = req.getSession(false); if (session == null || session.getAttribute("user") == null) { resp.sendRedirect("/login.jsp"); } else { chain.doFilter(request, response); } } @Override public void destroy() { } } ``` 3. 在商品列表上增加“添加”按钮,并实现添加商品功能和图片上传功能 要在商品列表上增加“添加”按钮,并实现添加商品功能和图片上传功能,可以按照以下步骤进行: - 在商品列表页面上添加一个“添加”按钮,代码如下: ``` <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addProductModal">添加</button> ``` 这里采用了 Bootstrap 模态框来实现添加商品的功能。 - 创建一个 add.jsp 页面,代码如下: ``` <div class="modal fade" id="addProductModal" tabindex="-1" role="dialog" aria-labelledby="addProductModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <form action="/add" method="post" enctype="multipart/form-data"> <div class="modal-header"> <h5 class="modal-title" id="addProductModalLabel">添加商品</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <div class="form-group"> <label for="name">商品名称</label> <input type="text" class="form-control" id="name" name="name"> </div> <div class="form-group"> <label for="price">商品价格</label> <input type="text" class="form-control" id="price" name="price"> </div> <div class="form-group"> <label for="image">商品图片</label> <input type="file" class="form-control-file" id="image" name="image"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button> <button type="submit" class="btn btn-primary">添加</button> </div> </form> </div> </div> </div> ``` 这里采用了 Bootstrap 模态框来展示一个表单,用户可以在这个表单中输入商品信息和上传商品图片。 - 创建一个 AddServlet 类,代码如下: ``` public class AddServlet extends HttpServlet { private ProductService productService = new ProductService(); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String name = req.getParameter("name"); String price = req.getParameter("price"); Part imagePart = req.getPart("image"); InputStream imageInputStream = imagePart.getInputStream(); byte[] imageBytes = IOUtils.toByteArray(imageInputStream); Product product = new Product(name, Double.parseDouble(price), imageBytes); productService.addProduct(product); resp.sendRedirect("/list.jsp"); } } ``` 以上代码中,AddServlet 是一个添加商品的 Servlet,它接收 POST 请求,从请求参数中获取商品信息和商品图片,将商品信息添加到数据库中,然后重定向到商品列表页面。 希望我的回答对你有所帮助。如果你还有其他问题,可以继续问我哦~
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值