zoukankan      html  css  js  c++  java
  • web过滤器中获取请求的参数(content-type:multipart/form-data)

    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

        

  • 相关阅读:
    软件升级细节卸载删除快捷方式等前需要检测
    安装gitlab的总结
    如何修改vagrant系统的root用户密码
    写一个PHP单例模式
    redis使用笔记
    mysql 删除商品名字重复数据,同时保留最新一条
    杀死僵尸进程
    Django 用户状态管理,认证,失效
    关于iOS多任务的一些扫盲
    ajax异步
  • 原文地址:https://www.cnblogs.com/springlight/p/6208908.html
Copyright © 2011-2022 走看看