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. Flink - state管理

    在Flink – Checkpoint 没有描述了整个checkpoint的流程,但是对于如何生成snapshot和恢复snapshot的过程,并没有详细描述,这里补充   StreamOperato ...

  2. phpexcel 内存溢出 优化

    最近我们公司的项目的在导出excel的时候偶尔出现内存溢出错误,经过测试发现当数据量大于5000条就出现这个问题(默认php.ini memory 是128M) Allowed memory size ...

  3. iOS中集成ijkplayer视频直播框架

    ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持 Android 和 iOS, 网上也有很多集成说明, 但是个人觉得还是不够详细, 在这里详细的讲一下在 iOS 中如何集成ijk ...

  4. windows下的socket网络编程(入门级)

    windows下的socket网络编程 clinet.c 客户端 server.c 服务器端 UDP通信的实现 代码如下 已经很久没有在windows下编程了,这次因为需要做一个跨平台的网络程序,就先 ...

  5. center的用法

    (1)先 frame ,决定大小,也就是宽.高 (2)再center,决定位置, 需要注意的是,不能直接写center,需要通过CGPointMake(x,y)赋值

  6. 中兴F412光猫超级密码破解、破解用户限制、关闭远程控制、恢复路由器拨号

    不少家庭都改了光纤入户,那肯定少不了光猫的吧.今天以中兴F412光猫为例介绍下此型号光猫超级密码的破解方法.一.F412超级密码破解方法1.运行CMD,输入telnet 192.168.1.1: 2. ...

  7. Java提高篇——equals()与hashCode()方法详解

    java.lang.Object类中有两个非常重要的方法: 1 2 public boolean equals(Object obj) public int hashCode() Object类是类继 ...

  8. Python之路-python(装饰器、生成器、迭代器、Json & pickle 数据序列化、软件目录结构规范)

    装饰器: 首先来认识一下python函数, 定义:本质是函数(功能是装饰其它函数),为其它函数添加附件功能        原则:        1.不能修改被装饰的函数的源代码.        2.不 ...

  9. (转)MVC设计模式学习总结

    原文  : chenchun的博客 http://www.cnblogs.com/jobscn/archive/2011/11/08/2240725.html -------------------- ...

  10. c# ConfigurationSection

    怎么把自己的配置文件配置到app.config中? 方案1:在app.config中添加 <!--应用配置--> <appSettings configSource="Co ...