Request&Response

来源:https://www.cnblogs.com/p1ng/archive/2020/02/22/12346949.html
-Advertisement-
Play Games

這兩天複習了下Request以及Response部分的內容。 主要內容 1. HTTP協議:響應消息 2. Request對象 3. Response對象 4. ServletContext對象 HTTP: 概念:Hyper Text Transfer Protocol 超文本傳輸協議 傳輸協議:定 ...


這兩天複習了下Request以及Response部分的內容。

主要內容

  1. HTTP協議:響應消息
  2. Request對象
  3. Response對象
  4. ServletContext對象

HTTP:

* 概念:Hyper Text Transfer Protocol 超文本傳輸協議
    * 傳輸協議:定義了,客戶端和伺服器端通信時,發送數據的格式
    * 特點:
        1. 基於TCP/IP的高級協議
        2. 預設埠號:80
        3. 基於請求/響應模型的:一次請求對應一次響應
        4. 無狀態的:每次請求之間相互獨立,不能交互數據

    * 歷史版本:
        * 1.0:每一次請求響應都會建立新的連接
        * 1.1:復用連接

1. 請求消息:客戶端發送給伺服器端的數據
    * 數據格式:
        1. 請求行
            請求方式 請求url 請求協議/版本
            GET /login.html HTTP/1.1

            * 請求方式:
                * HTTP協議有7種請求方式,常用的有2種
                    * GET:
                        1. 請求參數在請求行中,在url後。
                        2. 請求的url長度有限制的
                        3. 不太安全
                    * POST:
                        1. 請求參數在請求體中
                        2. 請求的url長度沒有限制的
                        3. 相對安全
        2. 請求頭:客戶端瀏覽器告訴伺服器一些信息
            請求頭名稱: 請求頭值
            * 常見的請求頭:
                1. User-Agent:瀏覽器告訴伺服器,我訪問你使用的瀏覽器版本信息
                    * 可以在伺服器端獲取該頭的信息,解決瀏覽器的相容性問題

                2. Referer:http://localhost/login.html
                    * 告訴伺服器,我(當前請求)從哪裡來?
                        * 作用:
                            1. 防盜鏈
                            2. 統計工作
        3. 請求空行
            空行,就是用於分割POST請求的請求頭,和請求體的。
        4. 請求體(正文):
            * 封裝POST請求消息的請求參數的

    * 請求字元串格式:
        POST /login.html    HTTP/1.1
        Host: localhost
        User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
        Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
        Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
        Accept-Encoding: gzip, deflate
        Referer: http://localhost/login.html
        Connection: keep-alive
        Upgrade-Insecure-Requests: 1
        
        username=zhangsan   


2. 響應消息:伺服器端發送給客戶端的數據
    * 數據格式:
        1. 響應行
            1. 組成:協議/版本 響應狀態碼 狀態碼描述
            2. 響應狀態碼:伺服器告訴客戶端瀏覽器本次請求和響應的一個狀態。
                1. 狀態碼都是3位數字 
                2. 分類:
                    1. 1xx:伺服器接受客戶端消息,但沒有接受完成,等待一段時間後,發送1xx多狀態碼
                    2. 2xx:成功。代表:200
                    3. 3xx:重定向。代表:302(重定向),304(訪問緩存)
                    4. 4xx:客戶端錯誤。
                        * 代表:
                            * 404(請求路徑沒有對應的資源) 
                            * 405:請求方式沒有對應的doXxx方法
                    5. 5xx:伺服器端錯誤。代表:500(伺服器內部出現異常)
                        
                
        2. 響應頭:
            1. 格式:頭名稱: 值
            2. 常見的響應頭:
                1. Content-Type:伺服器告訴客戶端本次響應體數據格式以及編碼格式
                2. Content-disposition:伺服器告訴客戶端以什麼格式打開響應體數據
                    * 值:
                        * in-line:預設值,在當前頁面內打開
                        * attachment;filename=xxx:以附件形式打開響應體。文件下載
        3. 響應空行
        4. 響應體:傳輸的數據


    * 響應字元串格式
        HTTP/1.1 200 OK
        Content-Type: text/html;charset=UTF-8
        Content-Length: 101
        Date: Wed, 06 Jun 2018 07:08:42 GMT

        <html>
          <head>
            <title>$Title$</title>
          </head>
          <body>
          hello , response
          </body>
        </html>

Request:

1. request對象和response對象的原理
    1. request和response對象是由伺服器創建的。我們來使用它們
    2. request對象是來獲取請求消息,response對象是來設置響應消息

2. request對象繼承體繫結構: 
    ServletRequest      --  介面
        |   繼承
    HttpServletRequest  -- 介面
        |   實現
    org.apache.catalina.connector.RequestFacade 類(tomcat)

3. request功能:
    1. 獲取請求消息數據
        1. 獲取請求行數據
            * GET /day14/demo1?name=zhangsan HTTP/1.1
            * 方法:
                1. 獲取請求方式 :GET
                    * String getMethod()  
                2. (*)獲取虛擬目錄:/day14
                    * String getContextPath()
                3. 獲取Servlet路徑: /demo1
                    * String getServletPath()
                4. 獲取get方式請求參數:name=zhangsan
                    * String getQueryString()
                5. (*)獲取請求URI:/day14/demo1
                    * String getRequestURI() : /day14/demo1
                    * StringBuffer getRequestURL() : http://localhost/day14/demo1

                    * URL:統一資源定位符 : http://localhost/day14/demo1    中華人民共和國
                    * URI:統一資源標識符 : /day14/demo1                    共和國
    
                6. 獲取協議及版本:HTTP/1.1
                    * String getProtocol()

                7. 獲取客戶機的IP地址:
                    * String getRemoteAddr()
                
        2. 獲取請求頭數據
            * 方法:
                * (*)String getHeader(String name):通過請求頭的名稱獲取請求頭的值
                * Enumeration<String> getHeaderNames():獲取所有的請求頭名稱
            
        3. 獲取請求體數據:
            * 請求體:只有POST請求方式,才有請求體,在請求體中封裝了POST請求的請求參數
            * 步驟:
                1. 獲取流對象
                    *  BufferedReader getReader():獲取字元輸入流,只能操作字元數據
                    *  ServletInputStream getInputStream():獲取位元組輸入流,可以操作所有類型數據
                        * 在文件上傳知識點後講解

                2. 再從流對象中拿數據
            
            
    2. 其他功能:
        1. 獲取請求參數通用方式:不論get還是post請求方式都可以使用下列方法來獲取請求參數
            1. String getParameter(String name):根據參數名稱獲取參數值    username=zs&password=123
            2. String[] getParameterValues(String name):根據參數名稱獲取參數值的數組  hobby=xx&hobby=game
            3. Enumeration<String> getParameterNames():獲取所有請求的參數名稱
            4. Map<String,String[]> getParameterMap():獲取所有參數的map集合

            * 中文亂碼問題:
                * get方式:tomcat 8 已經將get方式亂碼問題解決了
                * post方式:會亂碼
                    * 解決:在獲取參數前,設置request的編碼request.setCharacterEncoding("utf-8");
        
                
        2. 請求轉發:一種在伺服器內部的資源跳轉方式
            1. 步驟:
                1. 通過request對象獲取請求轉發器對象:RequestDispatcher getRequestDispatcher(String path)
                2. 使用RequestDispatcher對象來進行轉發:forward(ServletRequest request, ServletResponse response) 
            如: request.getRequestDispatcher("/requestDemo9").forward(request,response);

            2. 特點:
                1. 瀏覽器地址欄路徑不發生變化
                2. 只能轉發到當前伺服器內部資源中。
                3. 轉發是一次請求


        3. 共用數據:
            * 域對象:一個有作用範圍的對象,可以在範圍內共用數據
            * request域:代表一次請求的範圍,一般用於請求轉發的多個資源中共用數據
            * 方法:
                1. void setAttribute(String name,Object obj):存儲數據
                2. Object getAttribude(String name):通過鍵獲取值
                3. void removeAttribute(String name):通過鍵移除鍵值對

        4. 獲取ServletContext:
            * ServletContext getServletContext()
        

案例:用戶登錄

* 用戶登錄案例需求:
    1.編寫login.html登錄頁面
        username & password 兩個輸入框
    2.使用Druid資料庫連接池技術,操作mysql,day14資料庫中user表
    3.使用JdbcTemplate技術封裝JDBC
    4.登錄成功跳轉到SuccessServlet展示:登錄成功!用戶名,歡迎您
    5.登錄失敗跳轉到FailServlet展示:登錄失敗,用戶名或密碼錯誤


* 分析

* 開發步驟
    1. 創建項目,導入html頁面,配置文件,jar包
    
    2. 創建資料庫環境
        CREATE DATABASE day14;
        USE day14;
        CREATE TABLE USER(
        
            id INT PRIMARY KEY AUTO_INCREMENT,
            username VARCHAR(32) UNIQUE NOT NULL,
            PASSWORD VARCHAR(32) NOT NULL
        );

    3. 創建包com.ping.domain,創建類User
        package com.ping.domain;
        /**
         * 用戶的實體類
         */
        public class User {
        
            private int id;
            private String username;
            private String password;
        
        
            public int getId() {
                return id;
            }
        
            public void setId(int id) {
                this.id = id;
            }
        
            public String getUsername() {
                return username;
            }
        
            public void setUsername(String username) {
                this.username = username;
            }
        
            public String getPassword() {
                return password;
            }
        
            public void setPassword(String password) {
                this.password = password;
            }
        
            @Override
            public String toString() {
                return "User{" +
                        "id=" + id +
                        ", username='" + username + '\'' +
                        ", password='" + password + '\'' +
                        '}';
            }
        }

    4. 創建包com.ping.util,編寫工具類JDBCUtils
        package com.ping.util;

        import com.alibaba.druid.pool.DruidDataSourceFactory;
        
        import javax.sql.DataSource;
        import javax.xml.crypto.Data;
        import java.io.IOException;
        import java.io.InputStream;
        import java.sql.Connection;
        import java.sql.SQLException;
        import java.util.Properties;
        
        /**
         * JDBC工具類 使用Durid連接池
         */
        public class JDBCUtils {
        
            private static DataSource ds ;
        
            static {
        
                try {
                    //1.載入配置文件
                    Properties pro = new Properties();
                    //使用ClassLoader載入配置文件,獲取位元組輸入流
                    InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("druid.properties");
                    pro.load(is);
        
                    //2.初始化連接池對象
                    ds = DruidDataSourceFactory.createDataSource(pro);
        
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        
            /**
             * 獲取連接池對象
             */
            public static DataSource getDataSource(){
                return ds;
            }
        
        
            /**
             * 獲取連接Connection對象
             */
            public static Connection getConnection() throws SQLException {
                return  ds.getConnection();
            }
        }

    5. 創建包com.ping.dao,創建類UserDao,提供login方法
        
        package com.ping.dao;

        import com.ping.domain.User;
        import com.ping.util.JDBCUtils;
        import org.springframework.dao.DataAccessException;
        import org.springframework.jdbc.core.BeanPropertyRowMapper;
        import org.springframework.jdbc.core.JdbcTemplate;
        
        /**
         * 操作資料庫中User表的類
         */
        public class UserDao {
        
            //聲明JDBCTemplate對象共用
            private JdbcTemplate template = new JdbcTemplate(JDBCUtils.getDataSource());
        
            /**
             * 登錄方法
             * @param loginUser 只有用戶名和密碼
             * @return user包含用戶全部數據,沒有查詢到,返回null
             */
            public User login(User loginUser){
                try {
                    //1.編寫sql
                    String sql = "select * from user where username = ? and password = ?";
                    //2.調用query方法
                    User user = template.queryForObject(sql,
                            new BeanPropertyRowMapper<User>(User.class),
                            loginUser.getUsername(), loginUser.getPassword());
        
        
                    return user;
                } catch (DataAccessException e) {
                    e.printStackTrace();//記錄日誌
                    return null;
                }
            }
        }
    
    6. 編寫com.ping.web.servlet.LoginServlet類
        package com.ping.web.servlet;

        import com.ping.dao.UserDao;
        import com.ping.domain.User;
        import javax.servlet.ServletException;
        import javax.servlet.annotation.WebServlet;
        import javax.servlet.http.HttpServlet;
        import javax.servlet.http.HttpServletRequest;
        import javax.servlet.http.HttpServletResponse;
        import java.io.IOException;
        
        
        @WebServlet("/loginServlet")
        public class LoginServlet extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                //1.設置編碼
                req.setCharacterEncoding("utf-8");
                //2.獲取請求參數
                String username = req.getParameter("username");
                String password = req.getParameter("password");
                //3.封裝user對象
                User loginUser = new User();
                loginUser.setUsername(username);
                loginUser.setPassword(password);
        
                //4.調用UserDao的login方法
                UserDao dao = new UserDao();
                User user = dao.login(loginUser);
        
                //5.判斷user
                if(user == null){
                    //登錄失敗
                    req.getRequestDispatcher("/failServlet").forward(req,resp);
                }else{
                    //登錄成功
                    //存儲數據
                    req.setAttribute("user",user);
                    //轉發
                    req.getRequestDispatcher("/successServlet").forward(req,resp);
                }
        
            }
            @Override
            protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                this.doGet(req,resp);
            }
        }

    7. 編寫FailServlet和SuccessServlet類
        @WebServlet("/successServlet")
        public class SuccessServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //獲取request域中共用的user對象
                User user = (User) request.getAttribute("user");
        
                if(user != null){
                    //給頁面寫一句話
        
                    //設置編碼
                    response.setContentType("text/html;charset=utf-8");
                    //輸出
                    response.getWriter().write("登錄成功!"+user.getUsername()+",歡迎您");
                }
            }       

        @WebServlet("/failServlet")
        public class FailServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                //給頁面寫一句話
        
                //設置編碼
                response.setContentType("text/html;charset=utf-8");
                //輸出
                response.getWriter().write("登錄失敗,用戶名或密碼錯誤");
        
            }
        
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request,response);
            }
        }

    8. login.html中form表單的action路徑的寫法
        * 虛擬目錄+Servlet的資源路徑

    9. BeanUtils工具類,簡化數據封裝
        * 用於封裝JavaBean的
        1. JavaBean:標準的Java類
            1. 要求:
                1. 類必須被public修飾
                2. 必須提供空參的構造器
                3. 成員變數必須使用private修飾
                4. 提供公共setter和getter方法
            2. 功能:封裝數據


        2. 概念:
            成員變數:
            屬性:setter和getter方法截取後的產物
                例如:getUsername() --> Username--> username


        3. 方法:
            1. setProperty()
            2. getProperty()
            3. populate(Object obj , Map map):將map集合的鍵值對信息,封裝到對應的JavaBean對象中

Response對象

* 功能:設置響應消息
    1. 設置響應行
        1. 格式:HTTP/1.1 200 ok
        2. 設置狀態碼:setStatus(int sc) 
        
    2. 設置響應頭
        setHeader(String name, String value) 
        
    3. 設置響應體
        * 使用步驟
            1. 獲取輸出流
                * 字元輸出流:PrintWriter getWriter()
                * 位元組輸出流:ServletOutputStream getOutputStream()

            2. 使用輸出流,將數據輸出到客戶端瀏覽器


* 案例:
    1. 完成重定向
        * 重定向:資源跳轉的方式
        * 代碼實現:
            //1. 設置狀態碼為302
            response.setStatus(302);
            //2.設置響應頭location
            response.setHeader("location","/day15/responseDemo2");

            //簡單的重定向方法
            response.sendRedirect("/day15/responseDemo2");

        * 重定向的特點:redirect
            1. 地址欄發生變化
            2. 重定向可以訪問其他站點(伺服器)的資源
            3. 重定向是兩次請求,不能使用request對象來共用數據
            
        * 轉發的特點:forward
            1. 轉發地址欄路徑不變
            2. 轉發只能訪問當前伺服器下的資源
            3. 轉發是一次請求,可以使用request對象來共用數據
        
        * forward 和 redirect 區別
            
        * 路徑寫法:
            1. 路徑分類
                1. 相對路徑:通過相對路徑不可以確定唯一資源
                    * 如:./index.html
                    * 不以/開頭,以.開頭路徑

                    * 規則:找到當前資源和目標資源之間的相對位置關係
                        * ./ :當前目錄
                        * ../ :後退一級目錄
                2. 絕對路徑:通過絕對路徑可以確定唯一資源
                    * 如:http://localhost/day15/responseDemo2        /day15/responseDemo2
                    * 以/開頭的路徑

                    * 規則:判斷定義的路徑是給誰用的?判斷請求將來從哪兒發出
                        * 給客戶端瀏覽器使用:需要加虛擬目錄(項目的訪問路徑)
                            * 建議虛擬目錄動態獲取:request.getContextPath()
                            * <a> , <form> 重定向...
                        * 給伺服器使用:不需要加虛擬目錄
                            * 轉發路徑
                            
                    
                    

    2. 伺服器輸出字元數據到瀏覽器
        * 步驟:
            1. 獲取字元輸出流
            2. 輸出數據

        * 註意:
            * 亂碼問題:
                1. PrintWriter pw = response.getWriter();獲取的流的預設編碼是ISO-8859-1
                2. 設置該流的預設編碼
                    response.setCharacterEncoding("utf-8");
                3. 告訴瀏覽器響應體使用的編碼
                    response.setHeader("content-type","text/html;charset=utf-8");
                
                //簡單的形式設置編碼,是在獲取流之前設置(以後使用這種方式設置即可)
                response.setContentType("text/html;charset=utf-8");
                

    3. 伺服器輸出位元組數據到瀏覽器
        * 步驟:
            1. 獲取位元組輸出流
            2. 輸出數據

    4. 驗證碼
        * 本質:圖片
        * 目的:防止惡意表單註冊

    代碼:
        @WebServlet("/checkCodeServlet")
        public class CheckCodeServlet extends HttpServlet {
            protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                int width = 100;
                int height = 50;
                //1.創建一對象,在記憶體中圖片(驗證碼圖片對象)
                BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                //2.美化圖片
                //2.1 填充背景色
                Graphics g = image.getGraphics();
                g.setColor(Color.pink);
                g.fillRect(0,0,width,height);
                //2.2 畫邊框
                g.setColor(Color.blue);
                g.drawRect(0,0,width-1,height-1);
        
                String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
                Random ran = new Random();
                for (int i = 1;i <= 4;i++){
                    int index = ran.nextInt(str.length());
                    //獲取字元
                    char ch = str.charAt(index);
                    //2.3 寫驗證碼
                    g.drawString(ch+"", (width / 5) * i,25);
                }
                //2.4 畫干擾線
                g.setColor(Color.green);
                for (int i = 0;i< 10;i++){
                    //隨機生成坐標點
                    int x1 = ran.nextInt(width);
                    int x2 = ran.nextInt(width);
                    int y1 = ran.nextInt(height);
                    int y2 = ran.nextInt(height);
                    g.drawLine(x1,y1,x2,y2);
                }
        
                //3.將圖片輸出到頁面展示
                ImageIO.write(image, "jpg",response.getOutputStream());
            }
            
            protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
                this.doPost(request,response);
            }
        }

    添加點擊圖片或超鏈接切換驗證碼:
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script>
            /*
                分析:
                    點擊超鏈接或圖片,需要換一張
                    1.給超鏈接和圖片綁定單擊事件
                    2.重新設置圖片的src屬性值
             */
            window.onload = function () {
                //1.獲取圖片對象
                var img = document.getElementById("checkCode");
                //2.綁定單擊事件
                img.onclick = function () {
                    //加時間戳,解決瀏覽器緩存問題
                    var date = new Date().getTime();
                    img.src = "/day15/checkCodeServlet?"+date;
                }
                a.onclick = function () {
                    var date = new Date().getTime();
                    img.src = "/day15/checkCodeServlet?"+date;
                }
            }
        </script>
    </head>
    <body>
        <img id="checkCode" src="/day15/checkCodeServlet" />
        <a id="change" href="">看不清換一張?</a>
    </body>
    </html>

ServletContext對象:

1. 概念:代表整個web應用,可以和程式的容器(伺服器)來通信

2. 獲取:
    1. 通過request對象獲取
        request.getServletContext();
    2. 通過HttpServlet獲取
        this.getServletContext();

3. 功能:
    1. 獲取MIME類型:
        * MIME類型:在互聯網通信過程中定義的一種文件數據類型
            * 格式: 大類型/小類型   text/html       image/jpeg

        * 獲取:String getMimeType(String file)  
    2. 域對象:共用數據
        1. setAttribute(String name,Object value)
        2. getAttribute(String name)
        3. removeAttribute(String name)

        * ServletContext對象範圍:所有用戶所有請求的數據
    3. 獲取文件的真實(伺服器)路徑
        1. 方法:String getRealPath(String path)  
             String b = context.getRealPath("/b.txt");//web目錄下資源訪問
             System.out.println(b);
    
            String c = context.getRealPath("/WEB-INF/c.txt");//WEB-INF目錄下的資源訪問
            System.out.println(c);
    
            String a = context.getRealPath("/WEB-INF/classes/a.txt");//src目錄下的資源訪問
            System.out.println(a);

案例:

* 文件下載需求:
    1. 頁面顯示超鏈接
    2. 點擊超鏈接後彈出下載提示框
    3. 完成圖片文件下載


* 分析:
    1. 超鏈接指向的資源如果能夠被瀏覽器解析,則在瀏覽器中展示,如果不能解析,則彈出下載提示框。不滿足需求
    2. 任何資源都必須彈出下載提示框
    3. 使用響應頭設置資源的打開方式:
        * content-disposition:attachment;filename=xxx


* 步驟:
    1. 定義頁面,編輯超鏈接href屬性,指向Servlet,傳遞資源名稱filename
    2. 定義Servlet
        1. 獲取文件名稱
        2. 使用位元組輸入流載入文件進記憶體
        3. 指定response的響應頭: content-disposition:attachment;filename=xxx
        4. 將數據寫出到response輸出流

* 問題:
    * 中文文件問題
        * 解決思路:
            1. 獲取客戶端使用的瀏覽器版本信息
            2. 根據不同的版本信息,設置filename的編碼方式不同

* 代碼:
Servlet:
    @WebServlet(name = "downloadServlet")
    public class DownloadServlet extends HttpServlet {
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            //1. 獲取請求參數,文件名稱
            String filename = request.getParameter("filename");
            //2.使用位元組輸入流載入文件進記憶體
            //2.1 找到文件伺服器路徑
            ServletContext servletContext = this.getServletContext();
            String realPath = servletContext.getRealPath("/img/"+filename);
            //2.2  用位元組流關聯
            FileInputStream fis = new FileInputStream(realPath);
            //3.設置response的響應頭
            //3.1 設置響應頭類型: content-type
            String mimeType = servletContext.getMimeType(filename);
            response.setHeader("content-type",mimeType);
    
            //解決中文文件名問題
            //1.獲取user-agent請求頭
            String agent = request.getHeader("user-agent");
            //2.使用工具類方法編碼文件名即可
            filename = DownLoadUtils.getFileName(agent, filename);
            
            //3.2 設置響應頭打開方式: content-disposition
            response.setHeader("content-disposition","attachment;filename="+filename);
            //4.將輸入流的數據寫到輸出流中
            ServletOutputStream sos = response.getOutputStream();
            byte[] buff = new byte[1024 * 8];
            int len = 0;
            while((len = fis.read(buff)) != -1){
                sos.write(buff,0,len);
            }
            fis.close();
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            this.doPost(request,response);
        }
    }


下載工具類:
    import sun.misc.BASE64Encoder;
    import java.io.UnsupportedEncodingException;
    import java.net.URLEncoder;
    
    public class DownLoadUtils {
        public static String getFileName(String agent, String filename) throws UnsupportedEncodingException {
            if (agent.contains("MSIE")) {
                // IE瀏覽器
                filename = URLEncoder.encode(filename, "utf-8");
                filename = filename.replace("+", " ");
            } else if (agent.contains("Firefox")) {
                // 火狐瀏覽器
                BASE64Encoder base64Encoder = new BASE64Encoder();
                filename = "=?utf-8?B?" + base64Encoder.encode(filename.getBytes("utf-8")) + "?=";
            } else {
                // 其它瀏覽器
                filename = URLEncoder.encode(filename, "utf-8");
            }
            return filename;
        }
    }

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1.設置django的mysql驅動為pymysql 因為django預設的是使用MySqlDb連接mysql資料庫,但是由於該模塊不支持python3.4以上版本,所以使用pymysql模塊 在項目的預設文件夾(也就是settings.py等文件的那個文件夾)的__init__.py文件中增加如下 ...
  • 更新多個對象 例如說我們現在想要將Apress Publisher的名稱由原來的”Apress”更改為”Apress Publishing”。若使用save()方法,如: ? 1 2 3 >>> p = Publisher.objects.get(name='Apress') >>> p.name  ...
  • 最近的Django項目中有複製記錄的需求。資料庫里有一張名為Party的表,記錄用戶創建的party,現在要讓用戶能夠複製一個新的party。本身非常簡單的一個功能,但運行的時候出錯了。我以為是複製過程出錯,所以測試了一下Django中複製記錄可能遇到的情況(後來發現是其他代碼的邏輯出了問題),結果 ...
  • 前言: 公司的產品是一款基於社交的內容聊天軟體,需要集成語音通訊功能,在寫iOS原生項目時,用到的就是Agora SDK,現在寫React Native也直接採用了Agora的庫。 集成iOS、Android的步驟: 請參考鏈接:https://github.com/syanbo/react-nat ...
  • 整理了一些Java方面的架構、面試資料(微服務、集群、分散式、中間件等),有需要的小伙伴可以關註公眾號【程式員內點事】,無套路自行領取 更多優選 "一口氣說出 9種 分散式ID生成方式,面試官有點懵了" "3萬字總結,Mysql優化之精髓" "為了不複製粘貼,我被逼著學會了JAVA爬蟲" "技術部突 ...
  • Nginx 其實就是一款輕量級的 Web 伺服器、反向代理伺服器,由於它的記憶體占用少,啟動極快,高併發能力強,在互聯網項目中廣泛應用。 那麼你可能會問了:“不是說 Nginx 嗎?怎麼又扯出來一個 Web 伺服器呢?啥是伺服器?”。彆著急,在學習 Nginx 之前你還真得知道什麼是伺服器這個概念,下 ...
  • R語言主要用於統計,因此引入了向量這個概念將更好地進行統計計算,在其他無法引入向量的語言當中則會使用迴圈來計算一些大規模的數據,在R語言當中則不需要,下麵我們來看看R語言當中向量的具體用法吧! 首先,如果我們把x作為一個向量,將其賦值為擁有五個元素的向量,代碼如下: > x <- c(1,2,3,4 ...
  • `爬蟲呢有時候數據方便有時候登入獲得cookies,以及獲取他存緩存中的數據` 一.獲取緩存中的數據其實很簡單js註入就好了 ...
一周排行
    -Advertisement-
    Play Games
  • Timer是什麼 Timer 是一種用於創建定期粒度行為的機制。 與標準的 .NET System.Threading.Timer 類相似,Orleans 的 Timer 允許在一段時間後執行特定的操作,或者在特定的時間間隔內重覆執行操作。 它在分散式系統中具有重要作用,特別是在處理需要周期性執行的 ...
  • 前言 相信很多做WPF開發的小伙伴都遇到過表格類的需求,雖然現有的Grid控制項也能實現,但是使用起來的體驗感並不好,比如要實現一個Excel中的表格效果,估計你能想到的第一個方法就是套Border控制項,用這種方法你需要控制每個Border的邊框,並且在一堆Bordr中找到Grid.Row,Grid. ...
  • .NET C#程式啟動閃退,目錄導致的問題 這是第2次踩這個坑了,很小的編程細節,容易忽略,所以寫個博客,分享給大家。 1.第一次坑:是windows 系統把程式運行成服務,找不到配置文件,原因是以服務運行它的工作目錄是在C:\Windows\System32 2.本次坑:WPF桌面程式通過註冊表設 ...
  • 在分散式系統中,數據的持久化是至關重要的一環。 Orleans 7 引入了強大的持久化功能,使得在分散式環境下管理數據變得更加輕鬆和可靠。 本文將介紹什麼是 Orleans 7 的持久化,如何設置它以及相應的代碼示例。 什麼是 Orleans 7 的持久化? Orleans 7 的持久化是指將 Or ...
  • 前言 .NET Feature Management 是一個用於管理應用程式功能的庫,它可以幫助開發人員在應用程式中輕鬆地添加、移除和管理功能。使用 Feature Management,開發人員可以根據不同用戶、環境或其他條件來動態地控制應用程式中的功能。這使得開發人員可以更靈活地管理應用程式的功 ...
  • 在 WPF 應用程式中,拖放操作是實現用戶交互的重要組成部分。通過拖放操作,用戶可以輕鬆地將數據從一個位置移動到另一個位置,或者將控制項從一個容器移動到另一個容器。然而,WPF 中預設的拖放操作可能並不是那麼好用。為瞭解決這個問題,我們可以自定義一個 Panel 來實現更簡單的拖拽操作。 自定義 Pa ...
  • 在實際使用中,由於涉及到不同編程語言之間互相調用,導致C++ 中的OpenCV與C#中的OpenCvSharp 圖像數據在不同編程語言之間難以有效傳遞。在本文中我們將結合OpenCvSharp源碼實現原理,探究兩種數據之間的通信方式。 ...
  • 一、前言 這是一篇搭建許可權管理系統的系列文章。 隨著網路的發展,信息安全對應任何企業來說都越發的重要,而本系列文章將和大家一起一步一步搭建一個全新的許可權管理系統。 說明:由於搭建一個全新的項目過於繁瑣,所有作者將挑選核心代碼和核心思路進行分享。 二、技術選擇 三、開始設計 1、自主搭建vue前端和. ...
  • Csharper中的表達式樹 這節課來瞭解一下表示式樹是什麼? 在C#中,表達式樹是一種數據結構,它可以表示一些代碼塊,如Lambda表達式或查詢表達式。表達式樹使你能夠查看和操作數據,就像你可以查看和操作代碼一樣。它們通常用於創建動態查詢和解析表達式。 一、認識表達式樹 為什麼要這樣說?它和委托有 ...
  • 在使用Django等框架來操作MySQL時,實際上底層還是通過Python來操作的,首先需要安裝一個驅動程式,在Python3中,驅動程式有多種選擇,比如有pymysql以及mysqlclient等。使用pip命令安裝mysqlclient失敗應如何解決? 安裝的python版本說明 機器同時安裝了 ...