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. centos7 systemctl命令

    systemctl命令是系统服务管理器指令,它实际上将 service 和 chkconfig 这两个命令组合到一起. 实例: 启动nfs服务:systemctl start nfs-server.s ...

  2. Lock较synchronized多出的特性

    1.尝试非阻塞形式获取锁 tryLock() :当前线程尝试获取锁,如果锁被占用返回false;如果成功则占有锁 //类似用法if(lock.tryLock()) { try { System.out ...

  3. distribution数据库过大问题

    从事件探查器中监控到如下语句执行时间查过 1分钟: EXEC dbo .sp_MSdistribution_cleanup @min_distretention = 0, @max_distreten ...

  4. on-my-zsh agnoster 主题设置问题

    安装Menlo-Powerline字体补丁 https://gist.github.com/qrush/1595572/raw/417a3fa36e35ca91d6d23ac96107... 然后 c ...

  5. MVC EF 执行SQL语句

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精 闲着没事,看了一篇关于LINQ和SQL对比的文章,网友们 ...

  6. Tomcat 使用Redis存储Session

    Tomcat Redis Session Github 地址. 下载 commons-pool2-2.2.jar,jedis-2.5.2.jar,tomcat-redis-session-manage ...

  7. Web3D编程入门总结——WebGL与Three.js基础介绍

    /*在这里对这段时间学习的3D编程知识做个总结,以备再次出发.计划分成“webgl与three.js基础介绍”.“面向对象的基础3D场景框架编写”.“模型导入与简单3D游戏编写”三个部分,其他零散知识 ...

  8. VBA的打开关闭保存另存为等事件无法正常跑的原因

    打开执行的代码需要写在thisworkbook的open事件下!!!!!如下图: VBA中事件分为三种:工作簿事件,工作表事件,窗体.控件事件. 工作簿事件发生在特定的工作簿中,如Open(打开工作簿 ...

  9. php 安装 sphinx

    我的环境是 ubuntun ,所以 第一步 sudo apt-get install pear 第二,根据 php.net 里说的,去下载 sphinx. 第三,pecl install sphinx ...

  10. install sublime for linux

    Download Your Free eBooks NOW - 10 Free Linux eBooks for Administrators Python API, that available f ...