zoukankan      html  css  js  c++  java
  • java web(四):request、response一些用法和文件的上传和下载

      上一篇讲了ServletContent、ServletCOnfig、HTTPSession、request、response几个对象的生命周期、作用范围和一些用法。今天通过一个小项目运用这些知识。简单的注册登录,文件的上传和下载。


     大致思路:

      注册登录和文件上传和下载
            注册成功后跳转到登录界面,登陆成功后跳转到主界面,主界面有上传和下载功能。
        本次注册登录不用数据库,注册成功后放到一个map集合中,key值为账号,value值为密码。
        注册成功把当前用户信息放入map集合并且使用ServletContent对象保存。

    一:准备阶段

      先在WebContent目录下创建几个html页面。

      注册页面 register.html :

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>注册</title>
    </head>
    <body>
        <br><br><br>
        <!-- action代表form表单提交给那个servlet处理
             method指定提交方式:get代表把参数拼接在url后面
             post代表把参数放在http请求体中
          -->
        <form action="register" method="post">
            <div align="center">
                <span>账号</span><input type="text" name="username">
                <br>
                <span>密码</span><input type="password" name="pw">
                <div align="center">
                    <input type="submit" value="注册"/>
                </div>
            </div>
        </form>
    </body>
    </html>

        登录界面login.html:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录</title>
    </head>
    <body>
        <br><br><br>
        <form action="login" method="post">
            <div align="center">
                <span>账号</span><input type="text" name="username">
                <br>
                <span>密码</span><input type="password" name="pw">
                <br>
                <div align="center">
                    <input type="submit" value="登陆"/>
                </div>
            </div>
        </form>
    </body>
    </html>

      注册失败提示页面registerError.html:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>注册错误提示</title>
    </head>
    <body>
        <div align="center">
            <h1>账号重复</h1>
            <br>
            <a href="register.html">跳转到注册界面</a>
        </div>
    </body>
    </html>

      登录失败提示页面loginError.html:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>登录错误提示</title>
    </head>
    <body>
        <div align="center">
            <h1>账号密码错误</h1>
            <br>
            <a href="login.html">跳转到登录界面</a>
        </div>
        
    </body>
    </html>

      功能页面success.html:

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>主界面</title>
    </head>
    <body>
        <div align="center">
            <!-- enctype这个属性管理的是表单的MIME编码。共有三个值可选:
                  1、application/x-www-form-urlencoded
                 2、multipart/form-data
                 3、text/plain
                 文件上传值需要指定multipart/form-data
             -->
            <h1>文件上传</h1>
            <form action="upload" method="post" enctype="multipart/form-data">
                <input type="text" name="username" />
                <br>
                <input type="file" name="MyImage" />
                <br>
                <input type="submit" value="上传" />
    </form> </div> <br><br> <div align="center"> <!-- 指定几个文件提供下载
            等后面学了jsp,el表达式和jstl和新标签库可以拓展项目
            通过ServletContent对象调用getResourcePaths("/download")可以获得
            该目录下的所有内容。【/download/文件名】,然后利用这几个技术动态的资源列举出来
            供下载。
    --> <h1>文件下载</h1> <a href="download?fileName=1.jpg">1.jpg</a> <br> <a href="download?fileName=movie.wmv">moviemwmv</a> </div> </body> </html>

       文件长传和下载在webContent目录下创建两个文件夹upload和download,在download文件夹下放几个资源供下载。

      准备阶段完成后就可以开始着手写servlet。

    二:编写注册和登录的servlet

      注册和登录的servlet代码【注意:需要把<url-pattern>...</url-pattern>首字母改成小写和html页面对应】:

        

    package com.briup.servlet.function;
    
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Set;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    
    /**
     * Servlet implementation class Register
     * 注册
     */
    public class Register extends HttpServlet {
        private static final long serialVersionUID = 1L;
           
        public Register() {
            super();
        }
        
        @Override
        public void init() throws ServletException {
            //创建一个Map集合,然后通过ServletContent对象存进去
            Map<String,String> map = new HashMap<String,String>();
            this.getServletContext().setAttribute("map", map);
        }
        
        @SuppressWarnings("unchecked")
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            //获取注册的账号和密码
            String name = request.getParameter("username");
            String pw = request.getParameter("pw");
            
            //和map集合对比【不对账号密码格式做验证】
            Map<String,String> map = (Map<String, String>) 
                    this.getServletContext().getAttribute("map");
            if(map.isEmpty()) {
                map.put(name, pw);
                //客户端重定向到登录界面
                response.sendRedirect("login.html");
            } else {
                Set<String> key = map.keySet();
                //注册只需要对比账号,密码重复无所谓
                for(String s : key) {
                    if(s.equals(name)) {
                        //重定向到注册错误页面
                        response.sendRedirect("registerError.html");
                    } else {
                        map.put(name, pw);
                        //客户端重定向到登录界面
                        response.sendRedirect("login.html");
                    }
                }
            }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    
    }
    package com.briup.servlet.function;
    
    import java.io.IOException;
    import java.util.Map;
    import java.util.Set;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class Login
     * 登录Servlet
     */
    public class Login extends HttpServlet {
        private static final long serialVersionUID = 1L;
        
        public Login() {
            super();
        }
    
        @SuppressWarnings("unchecked")
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            //获取账号密码
            String name = request.getParameter("username");
            String pw = request.getParameter("pw");
            
            //获取map集合
            Map<String,String> map = (Map<String, String>) 
                    this.getServletContext().getAttribute("map");
            if(map.isEmpty()) {
                //服务器内部跳转到错误界面
                request.getRequestDispatcher("loginError.html").forward(request, response);
            } else {
                Set<String> keySet = map.keySet();
                for(String s : keySet) {
                    if(s.equals(name) && map.get(s).equals(pw)) {
                        /*
                         * 注意:执行到服务器内部跳转语句或客服端重定向不会中止函数的执行
                         * 和return在函数的作用不一样
                         * 会继续执行下去如果跳转语句和重定向后面还有语句
                         */
                        //System.out.println(s + "," + map.get(s));
                        //response.sendRedirect("success.html");
                        request.getRequestDispatcher("success.html").forward(request, response);
                        //需要显式的加上return
                        return;
                    }
                }
                //System.out.println("......");
                //如果代码执行到这里说明账号或密码不对
                //response.sendRedirect("loginError.html");
                request.getRequestDispatcher("loginError.html").forward(request, response);
            }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // TODO Auto-generated method stub
            doGet(request, response);
        }
    
    }

    三:文件的下载

      文件的下载和客户端重定向有点类似,向浏览器发送数据,但是要告诉浏览器这是文件下载要保存下来而不是当做html页面解析。

    response有个方法:getWriter():PrintWriter;获得一个字符输出流,该输出流可以向客户端输出数据。文件下载是否可以通过其写到页面?

      传输文件一般用字节流,有个类似的方法getOutputStream()可以获得字节流,通过该字节流向浏览器发送数据。

    response.setContentType("text/html;charset=utf-8")设置发给浏览器的是html页面【默认】,那么文件下载需要设置为那个?application/x-download。

    需要注意的是:我们需要获取下载文件的绝对路径,项目会被部署到tomcat安装目录下的webapp目录下,而在src的源代码则在 "项目名/WEB-INF/classes"下,

    使用相对路径就会出错。

    Dowload.java代码:

    package com.briup.servlet.function;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.net.URLEncoder;
    
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Servlet implementation class Download
     * 文件下载
     */
    public class Download extends HttpServlet {
        private static final long serialVersionUID = 1L;
        
        //把下载目录配置在web.xml中作为参数
        private String path;
      
        @Override
        public void init() throws ServletException {
            path = this.getServletConfig().getInitParameter("path");
        }
        
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
                    // 获得用户需要下载文件的名字
                    String fileName = request.getParameter("fileName");
    
                    // 下载文件所在目录的绝对路径
                    String realPath = getServletContext().getRealPath(path);
    
                    // 设置为下载application/x-download
                    response.setContentType("application/x-download");
                    
                    // 下载文件时显示的文件保存名称
                    String fileDisplay = "cnblogs_"+fileName;
                    // 中文编码转换
                    fileDisplay = URLEncoder.encode(fileDisplay, "UTF-8");
                    
                    //设置响应头部信息
                    response.addHeader("Content-Disposition", "attachment;filename="+fileDisplay);
                    try {
                        ServletOutputStream out = response.getOutputStream();
                        File file = new File(realPath,fileName);
                        FileInputStream in = new FileInputStream(file);
                        byte[] b = new byte[1024];
                        int len = -1;
                        while ((len = in.read(b)) != -1) {
                            out.write(b, 0, len);
                        }
                        out.flush();
                        in.close();
                        out.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // TODO Auto-generated method stub
            doGet(request, response);
        }
    
    }

    在web.xml中servlet的配置:

    <servlet>
        <description></description>
        <display-name>Download</display-name>
        <servlet-name>Download</servlet-name>
        <servlet-class>com.briup.servlet.function.Download</servlet-class>
        <init-param>
        	<param-name>path</param-name>
        	<param-value>/download</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>Download</servlet-name>
        <url-pattern>/download</url-pattern>
      </servlet-mapping>
    

       有时候会出现中文乱码,由于没有约定好。可以通过requst.setEncoding(编码)来解析浏览器发送过来的数据,通过

    response.setEnconding(编码)告诉浏览器以那种编码解析服务器发送过来的数据。如果有多个servlet需要设置编码,每个都这样设置会显得麻烦,有时候会忘记。

    这时候过滤器就可以起到很好的作用。

      

      过滤器,顾名思义,就是过滤掉一些东西。在web中过滤器像一个中介一样在浏览器和服务器中间做一些工作,对web管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截,从而实现一些特殊的功能。比如:不登录就不允许你访问主界面,实现URL级别的权限访问控制、过滤敏感词汇、压缩响应信息等一些高级功能。

      实现javax.servlet.Filter接口的类就是过滤器。和Servlet一样Filter的创建和销毁也是由WEB服务器负责。不过与Servlet区别的是,它是1>在应用启动的时候就进行装载Filter类(与Servlet的load-on-startup配置效果相同)。2>容器创建好Filter对象实例后,调用init()方法。接着被Web容器保存进应用级的集合容器中去了等待着,用户访问资源。3>当用户访问的资源正好被Filter的url-pattern拦截时,容器会取出Filter类调用doFilter方法,下次或多次访问被拦截的资源时,Web容器会直接取出指定Filter对象实例调用doFilter方法(Filter对象常驻留Web容器了)。4>当应用服务被停止或重新装载了,则会执行Filter的destroy方法,Filter对象销毁。

    这次我们使用Filter做个编码过滤器,代码:

    package com.briup.servlet.filter;
    
    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    /**
     * Servlet Filter implementation class EncodingFilter
     */
    public class EncodingFilter implements Filter {
    
        private String encoding;
        
        public EncodingFilter() {
            // TODO Auto-generated constructor stub
        }
    
        
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
                throws IOException, ServletException {
            //设置编码格式【只对post方式有效】;
            request.setCharacterEncoding(encoding);
            response.setCharacterEncoding(encoding);
            //放行;
            chain.doFilter(request, response);
        }
    
        
        public void init(FilterConfig fConfig) throws ServletException {
            //我们把编码设置在web.xml中,如果需要改编码在配置文件中更改而不需要更改代码
            encoding = fConfig.getInitParameter("encoding");
        }
    
    }

    web.xml配置:

    <filter>
        <display-name>EncodingFilter</display-name>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>com.briup.servlet.filter.EncodingFilter</filter-class>
      </filter>
      <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <!-- "*"通配符代表拦截所有请求 -->
        <url-pattern>/*</url-pattern>
      </filter-mapping>

     运行项目看效果:

     

     

    四:文件的上传

      网上有许多的上传组件,common-fileupload组件是apache的一个开源项目之一,用该组件可实现一次上传一个或多个文件,并可限制文件大小。

    该组件需要用到两个jar包,我用的是commons-fileupload-1.2.2.jar,commons-io-2.0.1.jar。到网上下载这两个jar包然后放到WEB-INF/lib目录下【该目录可以放本项目用到的jar包,会自动构建,和tomcat服务器下的lib目录相似,不过后者的作用范围更大,添加进服务器的项目都可以使用里面的jar包】。

    源码:

      

    package com.briup.servlet.function;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.commons.fileupload.FileItem;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    /**
     * Servlet implementation class Upload
     */
    public class Upload extends HttpServlet {
    	private static final long serialVersionUID = 1L;
           
    	private String path;
    	
        public Upload() {
            super();
        }
        
        @Override
        public void init() throws ServletException {
        	path = this.getServletConfig().getInitParameter("path");
        }
        
    	@SuppressWarnings("unchecked")
    	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    			throws ServletException, IOException {
    		
    		// 获得上传目录的绝对路径
    		String realpath = this.getServletContext().getRealPath(path);
    		System.out.println(path);
    
    		try {
    			// 构造一个文件上传处理对象
    			DiskFileItemFactory factory = new DiskFileItemFactory();
    			ServletFileUpload upLoad = new ServletFileUpload(factory);
    
    			// 获得表单中提交内容
    			List<FileItem> list = upLoad.parseRequest(request);
    
    			for (FileItem fileItem : list) {
    				// fileItem.isFormField()返回true表示是普通的表单组件
    				// fileItem.isFormField()返回false表示是上传
    
    				// 代表普通的输入框,获取内容方式不同以往
    				if (fileItem.isFormField()) {
    					// getName()方法返回的是文件名字 普通表单组件有文件 返回NULL
    					String FieldName = fileItem.getFieldName();
    					String Content = fileItem.getString("UTF-8");
    					// 为了后面可以把普通参数从request中拿出来
    					request.setAttribute(FieldName, Content);
    				} else {
    					// 取得上传文件的名字
    					String fileName = fileItem.getName();
    					// 避免文件名字重复
    					fileName = System.currentTimeMillis() + fileName;
    					File file = new File(realpath, fileName);
    					// 把上传文件进行指定目录
    					fileItem.write(file);
    				}
    			}
    			System.out.println("request.getAttribute(\"username\") = " + request.getAttribute("username"));
    
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    
    	protected void doPost(HttpServletRequest request, HttpServletResponse response)
    			throws ServletException, IOException {
    		doGet(request, response);
    	}
    
    }
    

     web.xml中该servlet的配置:

    <servlet>
        <description></description>
        <display-name>Upload</display-name>
        <servlet-name>Upload</servlet-name>
        <servlet-class>com.briup.servlet.function.Upload</servlet-class>
        <init-param>
          <param-name>path</param-name>
          <param-value>/upload</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>Upload</servlet-name>
        <url-pattern>/upload</url-pattern>
      </servlet-mapping>
    

    效果浏览:

  • 相关阅读:
    编程及应用中的一些快捷键(持续更新中)
    html5入门(head部分的基本认识)
    html5入门(j简单了解html)
    动态规划 ship
    js 解决两值交换
    styled-components解决全局样式'injectGlobal' 废除的问题
    mysql sql更新密码失败
    window nginx 基础命令
    MySQL 8.0
    "unexpected console statement” in Node.js
  • 原文地址:https://www.cnblogs.com/yangji0202/p/10521035.html
Copyright © 2011-2022 走看看