1.前言:

  1.1 在使用springMVC中,需要在过滤器中获取请求中的参数token,根据token判断请求是否合法;

  1.2 通过requst.getParameter(key)方法获得参数值;

    这种方法有缺陷:它只能获取  POST 提交方式中的Content-Type: application/x-www-form-urlencoded;

        HttpServletRequest request= (HttpServletRequest) req;
  String param = request.getParameter("param");

    

2.问题:

  在一般的请求中,content-type为:application/x-www-form-urlencoded;在此种请求中,使用request.getParam(key)方法可以获取到key对应的属性值;

  因为最近涉及到文件的上传操作,上传文件的请求中content-type为:multipart/form-data;此种请求无法直接用request.getParam(key)获取对应的属性值,request中获取的属性值全部为空,无法正常获取;

3.问题描述:

  3.1 在web.xml中配置的过滤器

  <filter>
<filter-name>requestFilter</filter-name>
<filter-class>util.web.RequestFilter</filter-class>
</filter> <filter-mapping>
<filter-name>requestFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

  

  3.2  过滤器RequestFilter.java中获取token做匹配

    在如下过滤器中,上传文件中的content-type:multipart/form-data使用获取request.getParameter(key)无法获取相应的值。需要借助Spring框架中的CommonsMultipartResolver.resolveMultipart(HttpServletRequest request)将request转为MultipartHttpServletRequest,从而使用getParameter(key)方法获取指定的值;

    * 在将对象转化完成后,要将转化完成的对象赋值给过滤链中的request参数中,即如下代码中的  req = multiReq; 赋值完成很重要,否则在controller层中依旧无法获取其他参数。

    如果不需要再filter中获取请求中的值,则无需如下的操作,在请求经过springMVC框架后,自动会识别请求方式,如果是文件请求,会自动调用CommonsMultipartResolver.resolveMultipart(HttpServletRequest request)方法转化;

package util.web;public class RequestFilter implements Filter {
protected FilterConfig filterConfig;
protected boolean filterEnabled;
protected int logLevel;
protected boolean needVCode;
protected List<String> noFilerList =null;
private CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
public RequestFilter() {
this.filterConfig = null;
this.filterEnabled = true;
this.logLevel = -1;
} @Override
public void destroy() {
// TODO Auto-generated method stub
} @Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
if(this.filterEnabled){
HttpServletRequest httpReq = (HttpServletRequest)req;
HttpServletResponse httpResp = (HttpServletResponse)resp;
String ctxPath = httpReq.getContextPath();
String requestUri = httpReq.getRequestURI(); //请求的全路径,比如:
String uri = requestUri.substring(ctxPath.length());//全路径除去ctxPath
String tarUri = uri.trim();
String operatorHtmlModel = (httpReq.getHeader("referer")!=null?httpReq.getHeader("referer"):"").trim(); //获取当前页面的url,判断url是否是后台而url(后台的html就两个)
//不在过滤列表里的url请求,过滤列表包括t_sys_filter表中数据及visitor角色用户下的授权页面
if(!this.isInNoFilerList(tarUri)){
UserInfo uInfo = SessionUtil.getCurrentUser();
LoginAccount regAccout=SessionUtil.getCurrentPlateLoginAccount();
int type = 0 ;//平台账号未登录
if(operatorHtmlModel.endsWith(Const.LOGIN_TYPE_HTML[0])||operatorHtmlModel.endsWith(Const.LOGIN_TYPE_HTML[1])){
type = 1;//后台账号未登录
}
// int type = (SessionUtil.getAttribute(Const.LOGIN_TYPE)!=null)?Integer.valueOf(SessionUtil.getAttribute(Const.LOGIN_TYPE).toString()):0;
if(regAccout==null){//平台账号未登录
if(tarUri.endsWith(".do")){
httpResp.sendRedirect(ctxPath+"/"+Const.TIMEOUT_SERVICE);
return;
}else if(tarUri.endsWith("/")){
httpResp.sendRedirect(ctxPath+"/"+Const.INDEX_PAGE);
return;
}
}else{//平台账号登录
if(tarUri.endsWith("/")){
httpResp.sendRedirect(ctxPath+"/error/noSecurity.htm");
return;
}else if(tarUri.endsWith(".do") && !isWithoutUri(tarUri)){
String contentType = httpReq.getContentType();//获取请求的content-type
String post_csrftoken = "";
if(contentType.contains("multipart/form-data")){//文件上传请求 *特殊请求
              /*
                
CommonsMultipartResolver 是spring框架中自带的类,使用multipartResolver.resolveMultipart(final HttpServletRequest request)方法可以将request转化为MultipartHttpServletRequest
                使用MultipartHttpServletRequest对象可以使用getParameter(key)获取对应属性的值
              */
                        MultipartHttpServletRequest multiReq = multipartResolver.resolveMultipart(httpReq);
post_csrftoken=multiReq.getParameter(Const.SESSION_CSRFTOKEN);//获取参数中的token
req = multiReq;//将转化后的reuqest赋值到过滤链中的参数 *重要
}else{//非文件上传请求
post_csrftoken=httpReq.getParameter(Const.SESSION_CSRFTOKEN);//获取参数中的token
}
//csrf防御:判断是否带token
//post_csrftoken=httpReq.getParameter(Const.SESSION_CSRFTOKEN);
String csrftoken=(String)SessionUtil.getAttribute(Const.SESSION_CSRFTOKEN);
if(post_csrftoken==null || !csrftoken.equals(post_csrftoken)){
//判断为不安全的访问
httpResp.sendRedirect(ctxPath+"/common/goNoSecurity.do");
return;
}
}
}
// 设定网页的到期时间,一旦过期则必须到服务器上重新调用
httpResp.setDateHeader("Expires", -1);
// Cache-Control 指定请求和响应应遵循的缓存机制 no-cache指示请求或响应消息是不能缓存的
httpResp.setHeader("Cache-Control", "no-cache");
// 用于设定禁止浏览器从本地缓存中调用页面内容,设定后一旦离开页面就无法从Cache中再调出
httpResp.setHeader("Pragma", "no-cache");
}
chain.doFilter(req, resp);
}
} @SuppressWarnings("unchecked")
@Override
public void init(FilterConfig cfg) throws ServletException {
//初始化操作
} private Boolean isWithoutUri(String tarUri){
String[] withoutUriStrings = {//无需匹配token的请求
"/common/goNoSecurity.do",
"/plateFormCommon/isLoginForPlateForm.do",
"/supplierForPlateForm/getCompanyListByRegId.do"
/*,"/PfTaskFileCtrl/addOrUpdateTaskImgFile1.do"*/
/*,"/PfTaskFileCtrl/addOrUpdateTaskImgFileForUpdate.do"*/
}; for(String uri:withoutUriStrings){
if(uri.equals(tarUri)){
return true;
}
}
return false;
} }

  3.3 控制层 PfTaskFileCtrl.java

  如果在filter中未将转化的request值赋值给过滤链,则在这里无法获取fileType对应的值;

package platform.common.controller;/**
* mogodb文件上传下载
* 项目名称:outsideeasy
* 类名称:PfTaskFileCtrl
* 创建人:mishengliang
* 创建时间:2016-4-26 下午1:55:19
* 修改人:mishengliang
* 修改时间:2016-4-26 下午1:55:19
* @version
*
*/
@Controller
@RequestMapping("PfTaskFileCtrl")
public class PfTaskFileCtrl { @Autowired
private PfRegisterAttchedService registerAttchedService;
@Autowired
private FileOptService fileService;
@Autowired
private PfUpdateRegisterAttchedService updateRegisterAttchedService;
@Autowired
private CompanyForPlateFormService companyForPlateFormService; @RequestMapping(value = { "/companyImageView" }, method = { RequestMethod.GET })
public ModelAndView gojsp_companyImageView(ModelAndView modelAndView ){
modelAndView.setViewName("/companyWindow/companyImageView");
return modelAndView;
} /**
* @Description:企业文件上传
* PfTaskFileCtrl
* addOrUpdateTaskImgFile1
* @param request
* @param response
* @return
* @throws Exception String
* @author yukai
* 2016-8-4 上午10:03:00
*/
@DocLogger(explain="企业文件上传")
@RequestMapping(value="addOrUpdateTaskImgFile1",method=RequestMethod.POST)
@ResponseBody
public String addOrUpdateTaskImgFile1(HttpServletRequest request,HttpServletResponse response) throws Exception{
Map<String,Object> qryParam = WebUtil.getDefaultParamsMap(request);
LoginAccount regAccount = SessionUtil.getCurrentPlateLoginAccount();
Map<String,Object> params=new HashMap<String, Object>();
JSONObject json = new JSONObject();
json.put("success", true);
/*
* 1.检查参数
*/
if(regAccount == null){//获取任务id
json.put("message", "未登录");
return json.toString() ;
}
     // *如果在filter中未将转化的request值赋值给过滤链,则在这里无法获取fileType对应的值
if(WebUtil.isEmpty(request.getParameter("fileType"))){//获取任务id
json.put("message", "没有文件类型值");
return json.toString() ;
}
/*
*2.赋值
*/
int fileType = Integer.parseInt(request.getParameter("fileType"));
String fileName = request.getParameter("fileName");
String formatType = request.getParameter("formatType"); PfRegisterAttched pfRegisterAttched = new PfRegisterAttched();
pfRegisterAttched.setFile_type_id(fileType);//文件类型值
pfRegisterAttched.setFile_name(fileName);//文件名 if(fileName.indexOf(",") != -1){
json.put("message", "文件名中存在非法字符(英文逗号),请先去除后上传");
return json.toString() ;
} /*
* 3.对文件信息的处理
*/
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
if(WebUtil.isEmpty((CommonsMultipartFile) multipartRequest.getFile("file"))){
json.put("message", "没有文件");
return json.toString() ;
}
CommonsMultipartFile file = (CommonsMultipartFile) multipartRequest.getFile("file"); //对应前台文件对象 if(file!=null && file.getSize()>0){//检查文件大小和格式
if (file.getSize() >5*1024*1024) {
json.put("message", "文件太大,超过5M");
return json.toString() ;
} String originalName=file.getOriginalFilename();
String this_suffix = "";
params.put(Const.ISIMG, 0);
params.put(Const.USE_TYPE, fileType);
params.put(Const.USERNAME, regAccount.getLogin_name());
params.put(Const.COM_ID, qryParam.get("companyId"));
params.put(Const.COM_NAME,companyForPlateFormService.getCompanyNameByCompanyId(qryParam));
boolean flag=false;//默认不 是图片
//获取文件后缀,与传过来的参数file_name重新组装文件名
if(originalName.indexOf(".")>0){//有后缀 XX.jpg XX.RAR
this_suffix=originalName.substring(originalName.lastIndexOf(".")); String[] format = null;
if("image".equals(formatType)){//判断上传文件的类型:image 图片,text 文档
format = Const.imgArray;
params.put(Const.ISIMG, 1);
}else if("text".equals(formatType)){
format = Const.otherArray;
} for(String suffix:format){
if(suffix.equalsIgnoreCase(this_suffix)){
flag=true;
break;
}
}
} if(!flag){
json.put("message", "不是指定格式");
return json.toString() ;
}else{
/*
* 4.进行信息的处理
*/
Date date = new Date();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String mongodbId=fileService.SaveFile(file,params);
pfRegisterAttched.setMogodb_id(mongodbId);//把存储mongoDb的文件序号存到数据库中
pfRegisterAttched.setCreate_dt(date);
pfRegisterAttched.setFile_format(this_suffix);
Integer id = registerAttchedService.addAppRegisterAttched(pfRegisterAttched);//获取存入信息的id
json.put("fileId",id);
json.put("mongodbId", mongodbId);
json.put("creatDate", sf.format(date));
json.put("message", "上传成功");
}
}else{
json.put("message", "文件不存在");
} return json.toString();
} }

4.解决方案

  在问题描述中已有问题解决方案。

  此方法主要利用了Spring框架中已有的工具类。

  参考资料:http://www.itdadao.com/articles/c15a279110p0.html

5.总结

  5.1 不同的content-type请求获取参数值的方法不同。

  5.2 在multipart/form-data请求方式中,需要利用SpringMVC框架中的CommonsMultipartResolver类包装转化为MultipartHttpServletRequest获取参数值;

6. 参考学习

  1. servlet3.0 Tomcat7.0 简洁方案

    如果使用的是servlet3.0及以上版本,multipart/form-data请求方式取值可以使用 HttpServletRequest.getPart(key)方法获取指定值;

    参考资料:http://stackoverflow.com/questions/2422468/how-to-upload-files-to-server-using-jsp-servlet/2424824#2424824

  2.通常的三种请求方式获取值方法

    * application/x-www-form-urlencoded

    *application/json

    * text/xml

  可以使用将请求转化为流,再转为字符串获取相应的值,通过如下方法获取的字符串获取指定的参数值;

  转化方法如下:

    /**
* 获取请求Body
*
* @param request
* @return
*/
public static String getBodyString(ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = request.getInputStream();
reader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}

  参考资料:http://blog.csdn.net/pyxly1314/article/details/51802652

    

web过滤器中获取请求的参数(content-type:multipart/form-data)的更多相关文章

  1. 在执行方法和Web资源中获取传递过来参数的值

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复228或者20161026可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong. ...

  2. 在过滤器中获取在web.xml配置的初始化参数

    在过滤器中获取在web.xml配置的初始化参数   例如 <filter> <filter-name>cross-origin</filter-name> < ...

  3. 4、处理方法中获取请求参数、请求头、Cookie及原生的servlet API等

    1.请求参数和请求头 使用@RequestParam绑定请求参数,在处理方法的入参处使用该注解可以把请求参数传递给请求方法 —— value :参数名 —— required : 是否必须,默认为tr ...

  4. AOP 环绕通知 (Schema-base方式) 和 AspectJ方式在通知中获取切点的参数

    环绕通知(Schema- base方式) 1.把前置通知和后置通知都写到一个通知中,组成了环绕通知 2.实现步骤: 2.1 新建一个类实现 MethodInterceptor 接口 public cl ...

  5. web项目中获取spring的bean对象

    Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中不通过注解的形式(@Resource.@Autowired)获取Spring配置的bean呢? Bean工厂(c ...

  6. 从XMLHttpRequest中获取请求的URL

    在编写Ajax通用错误处理程序时,经常需要记录发生错误的XMLHttpRequest的请求URL.但查询文档,并未找到从XMLHttpRequest中获取请求URL的方法. 在javascript - ...

  7. 创建dynamics CRM client-side (十三) - 在HTML Web Resource中获取form elements & 获取外部js文件

    上一节我们讨论到创建HTML Web Resource. 但是纯HTML的页面不能满足我们的需求, 所以今天我们来做在HTML Web Resource中获取form elements Please ...

  8. org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryRAYPKeHKTYSNdzc1;charset=UTF-8' not supported

    原文:https://www.cnblogs.com/yueli/p/7552888.html 最近同事在做一个图片上传功能.在入参 body 中同时传入文件和其它基本信息结果出现如题异常.在此记录下 ...

  9. Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages

    Web网页中动态数据区域的识别与抽取 Dynamical Data Regions Identification and Extraction in Web Pages Web网页中动态数据区域的识别 ...

随机推荐

  1. 无法启动Mysql服务,错误InnoDB: Attempted to open a previously opened tablespace.

    2013-08-04 13:48:22 760 [ERROR] InnoDB: Attempted to open a previously opened tablespace. Previous t ...

  2. LoadRunner11.00入门教程

    安装成功后,根据教程,有自带的应用程序供新手快速掌握Loadrunner的使用.测试应用是一个基于web的旅行社应用程序,也就是供用户在线预订机票的应用.根据教程和操作,重新总结一下测试流程以及遇到的 ...

  3. jquery中的$(document).ready()、JavaScript中的window.onload()以及body中的onload()的区别

      body中的onload()和window.onload以及$(document).ready()的区别: 1.前两者都表示当页面加载元素(包括图片等信息)完毕后执行的操作,而且两者在各种浏览器中 ...

  4. WPF部署问题 解决:The application requires that the assembly...be installed in the GAC

    vs-->引用-->找到问题类库-->邮件属性--->特定版本-->false done

  5. RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本发布

    (新年巨献) RDIFramework.NET ━ .NET快速信息化系统开发框架 V2.8 版本发布 历时数月,RDIFramework.NET V2.8版本发布了,感谢大家的支持. RDIFram ...

  6. UE4 自定义物理表面类型(Surface Type)

    如果想在UE4中实现在接触到不同物体表面时发出不同的声音或者效果时,比如人在不同的表面上速度会不同,子弹打到不同的表面时会出现不同的特效等,我们可以使用UE4中的表面类型来实现(Surface Typ ...

  7. 【转】SQLServerDBA十大必备工具---让生活轻松点

    曾经和一些DBA和数据库开发人员交流时,问他们都用过一些什么样的DB方面的工具,大部分人除了SSMS和Profile之外,基本就没有使用过其他工具了: 诚然,SSMS和Profile足够强大,工作的大 ...

  8. MySql 首记

    1.连接数据: 格式是:  -P 端口号  -h  mysql主机名\ip -u root (用户)  -p 2.显示数据库: show databases; 3.选择数据库: use databas ...

  9. ASP.NET 文件后缀名详解

    sln:解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息. .csproj:项目文件,创建应用程序所需的引用.数据连接.文件夹和文件的信息. .aspx:Web 窗体页由两部分组 ...

  10. 12个css高级技巧.html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...