Servlet

Servlet介紹

概述
    Servlet是運行在服務(wù)器端的Java應(yīng)用程序
    servlet程序開發(fā)動態(tài)資源的技術(shù)
    Servlet(Server Applet)是Java Servlet的簡稱,稱為小服務(wù)程序或服務(wù)連接器,
    用Java編寫的服務(wù)器端程序,主要功能在于交互式地瀏覽和修改數(shù)據(jù),生成動態(tài)Web內(nèi)容。
作用:
    用于接收和處理http請求(接收和響應(yīng)請求)
最核心的方法
    void service(ServletRequest req,ServletResponse res) 
    ServletRequest req 代表請求對象,包含請求的所有內(nèi)容,用于獲取請求數(shù)據(jù)
    ServletResponse res 代表響應(yīng)對象,包含響應(yīng)的所有內(nèi)容,用于修改響應(yīng)數(shù)據(jù)

Servlet開發(fā)步驟

1)java類,繼承HttpServlet類
    覆蓋doGet和doPost方法
2)在web應(yīng)用web.xml中配置servlet
3)請求Servlet

創(chuàng)建Servlet

//第一種方式 繼承 GenericServlet
    import java.io.IOException;
    import javax.servlet.GenericServlet;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    public class OneServlet extends GenericServlet {
        private static final long serialVersionUID = -2949013647446695209L;
        @Override
        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        }
    }
//第二種方式 繼承 HttpServlet 
    //繼承自GenericServlet類,是在其基礎(chǔ)上擴展了Http協(xié)議的Servlet
    //會先調(diào)用service方法,然后根據(jù)請求方式來進(jìn)行調(diào)用doGet/doPost
    import java.io.IOException;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public class OneServlet extends HttpServlet {
        private static final long serialVersionUID = -4435501112176421548L;
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            super.doPost(req, resp);
        }
    }

配置Servlet

在web.xml中配置
    <servlet>
        <!-- 名稱要唯一 -->
        <servlet-name>one</servlet-name>
        <!-- 全路徑 -->
        <servlet-class>com.shuai.action.OneServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!-- 要與上邊的名稱一致 -->
        <servlet-name>one</servlet-name>
        <!-- 訪問Servlet的URL,相對于Web應(yīng)用的路徑 -->
        <url-pattern>/one</url-pattern>
    </servlet-mapping>

配置Servlet中設(shè)置初始化值

<servlet>
    <servlet-name>one</servlet-name>
    <servlet-class>com.shuai.action.OneServlet</servlet-class>
    <!-- 設(shè)置初始化值 -->
    <init-param>
        <param-name>initParam</param-name>
        <param-value>paramtest</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>one</servlet-name>
    <url-pattern>/one</url-pattern>
</servlet-mapping>
@Override
public void init(ServletConfig config) throws ServletException {
    //這個super一定不要刪掉
    super.init(config);
    //通過ServletConfig對象讀取初始化參數(shù)
    String initParameter = config.getInitParameter("initParam");
    System.out.println(initParameter);
    //獲得所有參數(shù)的key
    Enumeration<String> enumeration = config.getInitParameterNames();
}
有參的init 與 無參init
    有參init:生命周期方法,必定會被服務(wù)器調(diào)用。(內(nèi)部默認(rèn)會調(diào)用無參的init方法)
    無參init:提供給開發(fā)者進(jìn)行初始化工作的方法。

Servlet生命周期

實例化 - Servlet 容器創(chuàng)建 Servlet 的實例
初始化 - 容器調(diào)用 init() 方法
請求處理 - 如果請求 Servlet,則容器調(diào)用 service() 方法
服務(wù)終止/重新部署 - 銷毀實例之前調(diào)用 destroy() 方法,通過stop server看

Servlet線程安全問題

Servlet 在服務(wù)器中是單實例多線程的。
    每次都會在Service方法中新建一個子線程來處理請求:new ThreadServlet()
    引起并發(fā)問題的原因:在Servlet中使用了成員變量(多個線程共享的數(shù)據(jù))。
    測試:
        可以通過在Servlet中輸出一個count值,然后線程睡眠,最后count++。
        用兩個瀏覽器同時去訪問。會發(fā)現(xiàn)最后輸出的結(jié)果是一樣的。
    解決多并發(fā),用同步
        在doGet方法中
            synchronized (OneServlet.class) {
                //業(yè)務(wù)代碼
            }
    建議:
        盡量不要在Servlet中使用成員變量
        如果使用了成員變量,那么就需要使用synchronized進(jìn)行同步代碼,而且盡量縮小同步的范圍

Servlet的一些細(xì)節(jié)

改變Servlet的創(chuàng)建時機
    <servlet>
        <servlet-name>one</servlet-name>
        <servlet-class>com.shuai.action.ThreeServlet</servlet-class>
        <!-- 在項目部署啟動的時候,默認(rèn)創(chuàng)建Servlet,數(shù)值越大優(yōu)先級越低 -->
        <load-on-startup>1</load-on-startup>
    </servlet>
路徑映射規(guī)則
                url-pattern    頁面訪問
    精確映射       /one           /one   
                   /test/one      /test/one

    模糊映射       /*             /任意路徑
                   /test/*        /test/任意路徑
                   *.后綴         任意路徑.后綴
    注意:
        url-pattern要么以/或者*開頭
        當(dāng)前有多個url-pattern,優(yōu)先級問題
            后綴名結(jié)尾的url-pattern優(yōu)先級最低
            哪個更加精確哪個優(yōu)先

ServletConfig對象

概述
    Servlet配置對象
作用
    用于讀取servlet參數(shù)
如何得到ServletConfig對象
    通過有參的init方法獲得
    通過getServletConfig()獲得

ServletContext對象

概述
    ServletContext是servlet的上下文對象。
    代表當(dāng)前web應(yīng)用。
    一個web有且只有一個ServletContext對象。
獲取ServletContext對象
    ServletContext servletContext = getServletConfig().getServletContext();
    ServletContext servletContext = getServletContext();
作用
    作為全局的域?qū)ο笫褂?    讀取全局的配置參數(shù)
    轉(zhuǎn)發(fā)web應(yīng)用內(nèi)的資源
    讀取web應(yīng)用內(nèi)的文件
具體使用
    設(shè)置全局屬性參數(shù)
        ServletContext servletContext = getServletContext();
        servletContext.setAttribute("name", "zhangsan");
        String str = (String)servletContext.getAttribute("name");
    讀取全局參數(shù)
        <!-- 全局參數(shù) -->
        <context-param>
            <param-name>onep</param-name>
            <param-value>onep</param-value>
        </context-param>
        <context-param>
            <param-name>twop</param-name>
            <param-value>twop</param-value>
        </context-param>
        ServletContext servletContext = getServletContext();
        String onep = servletContext.getInitParameter("onep");
        String twop = servletContext.getInitParameter("twop");
    轉(zhuǎn)發(fā)
        ServletContext servletContext = getServletContext();
        //轉(zhuǎn)發(fā)內(nèi)部資源
        RequestDispatcher dispatcher = servletContext.getRequestDispatcher("info.jsp");
        dispatcher.forward(req, res);
    讀取web應(yīng)用內(nèi)的文件
        ServletContext servletContext = getServletContext();
        //獲取一個文件的絕對路徑 - 獲取的項目根目錄
        //要以/開頭
        String realPath = servletContext.getRealPath("/");
        System.out.println(realPath);
        //讀取一個文件,并且返回一個文件流
        InputStream inputStream = servletContext.getResourceAsStream("/路徑");

HttpServletResponse對象

response對象
    表示響應(yīng)對象,包含所有的響應(yīng)數(shù)據(jù)。使用response對象可以修改響應(yīng)數(shù)據(jù)。
響應(yīng)格式
    響應(yīng)行
        http版本
        狀態(tài)碼 setStatus(sc)方法
        描述
    響應(yīng)頭
        鍵值對 
            setHeader(key,value)方法
            setDateHeader(key,value)方法-專門修改日期類型的響應(yīng)頭
            setIntHeader(key,value)方法 - 專門修改int類型的響應(yīng)頭
    空行
    正文
        getWriter() 修改字符類型的正文(文本,網(wǎng)頁)minetype:text/*類型
        getOutputStream() 修改字節(jié)類型的正文(圖片,視頻)
getOutputStream()返回文本數(shù)據(jù)解決亂碼
    系統(tǒng)默認(rèn)是GBK
        ServletOutputStream outputStream = res.getOutputStream();
        String str = "帥哥";
        outputStream.write(str.getBytes());
    輸出其它編碼
        ServletOutputStream outputStream = res.getOutputStream();
        第一種方式
        僅僅在ie瀏覽器有效
        String meta = "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>";
        //String meta = "<meta charset='UTF-8'>";
        outputStream.write(meta.getBytes());
        第二種方式
        所有瀏覽器有效
        response.setHeader("content-type", "text/html; charset=UTF-8");
        第三種方式
        所有瀏覽器有效
        response.setContentType("text/html; charset=UTF-8");
        String str = "帥哥";
        outputStream.write(str.getBytes("UTF-8"));
getWriter()返回文本數(shù)據(jù)解決亂碼
    write方法默認(rèn)是iso-8859-1
        只能輸出字節(jié)
    輸出其它編碼
        修改輸出字符內(nèi)容的查詢編碼-修改的是服務(wù)器- 這個代碼可以省略
            response.setCharacterEncoding("UTF-8");
        通知瀏覽器使用正確的編碼解析
            response.setContentType("text/html; charset=UTF-8");
            PrintWriter writer = response.getWriter();
            默認(rèn)編碼是iso-8859-1
            writer.write("帥哥");
文件下載
    讀取文件
        String path = getServletContext().getRealPath("/file/開發(fā)0710學(xué)生情況.xlsx");
        File file = new File(path);
        FileInputStream inputStream = new FileInputStream(file);
        獲取輸出通道
        ServletOutputStream outputStream = response.getOutputStream();
        下載提示框 響應(yīng)頭 content-disposition
        注意:在瀏覽器和服務(wù)器之間請求頭和響應(yīng)頭內(nèi)容出現(xiàn)中文,不能直接傳輸,而應(yīng)該把中文內(nèi)容進(jìn)行URL編碼才能傳輸
        String filename = URLEncoder.encode(file.getName(),"UTF-8");
        response.setHeader("content-disposition", "attachment;filename="+filename);
        邊讀邊寫
        byte[] buf = new byte[1024];
        int len = 0;
        while((len =inputStream.read(buf))!= -1){
            outputStream.write(buf);
        }
        關(guān)閉流
        inputStream.close();
輸出隨機驗證碼(防止惡意注冊和登錄)
    public void writeImage(HttpServletResponse response)throws ServletException, IOException {
        //內(nèi)存生成一張圖片
        int width = 120;
        int height = 50;
        BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
        //修改圖片背景
        //得到畫筆
        Graphics graphics = image.getGraphics();
        //繪制背景
        graphics.setColor(Color.gray);
        //繪制形狀
        graphics.fillRect(0, 0, width, height);
        //設(shè)置字體
        graphics.setFont(new Font("黑體", Font.ITALIC, 30));
        //繪制數(shù)字
        graphics.setColor(Color.BLACK);
        String str = "1234";
        graphics.drawString(str, 20, 25);
        //設(shè)置隨機干擾線
        Random ran = new Random();
        for(int i=1;i<=20;i++){
            int x1 = ran.nextInt(width);
            int y1 = ran.nextInt(height);
            int x2 = ran.nextInt(width);
            int y2 = ran.nextInt(height);
            //隨機色
            graphics.setColor(getRanColor());
            graphics.drawLine(x1, y1, x2, y2);
        }
        //把這個圖片寫出給瀏覽器
        ServletOutputStream outputStream = response.getOutputStream();
        ImageIO.write(image, "gif", outputStream);
    }
    //獲取隨機顏色
    private  Color getRanColor(){
        Random ran = new Random();
        int r = ran.nextInt(256);
        int g = ran.nextInt(256);
        int b = ran.nextInt(256);
        return new Color(r,g,b);
    }
    頁面使用
        ![](one)
重定向
    發(fā)出兩次請求
    地址欄會發(fā)生變化
    可以重定向任何資源(包括應(yīng)用外的資源)
    不可以通過request來共享數(shù)據(jù)
    代碼
        response.sendRedirect("/info.jsp");

HttpServletRequest對象

概述
    表示請求對象,包含所有的請求數(shù)據(jù)。使用request獲取請求的數(shù)據(jù)。
請求格式
    請求行
        請求方式  request.getMethod()
        請求資源  request.getRequestURL() / request.getRequestURI()
        http版本  request.getProtocol()
        獲得get請求的參數(shù) request.getQueryString()
    請求頭
        獲得一個請求頭 getHeader(key) 
        獲得整形的請求頭 getIntHeader(key) 
        獲得日期類型的請求頭 getDateHeader(key) 
    空行
    正文
        獲得正文 getInputStream()
防盜鏈
    String referer = request.getHeader("referer");
    if(referer == null || !referer.contains("/servlettest")){
        //非法連接
        return;
    }
獲取表單數(shù)據(jù)
    get : getQueryString()
    post : getInputStream()
    通用方式 
        獲取某個參數(shù) getParameter("")
        獲取某個參數(shù)的集合 getParameterValues("") 例如:checkbox
        獲取所有的參數(shù)名 getParameterNames()
        獲取所有的參數(shù) getParameterMap()
亂碼問題
    if("post".equalsIgnoreCase(request.getMethod())){
        //只能解決post提交的參數(shù),不能解決get提交的參數(shù),因為這個方法只能設(shè)置請求正文的內(nèi)容
        request.setCharacterEncoding("UTF-8");
    }
    String name = request.getParameter("name");//默認(rèn)是iso-8859-1
    if("get".equalsIgnoreCase(request.getMethod())){
        //get請求的參數(shù)需要手動解碼
        name = new String(name.getBytes("iso-8859-1"),"UTF-8");
    }
轉(zhuǎn)發(fā)
    發(fā)出一次請求
    地址欄不會發(fā)生變化
    只能轉(zhuǎn)發(fā)應(yīng)用內(nèi)的資源
    可以通過request來共享數(shù)據(jù)
    代碼
        //可以把數(shù)據(jù)發(fā)到轉(zhuǎn)發(fā)的頁面
        req.setAttribute("name", "zhangshuai");
        //第一種方式
        getServletContext().getRequestDispatcher("/info.jsp").forward(req, response);
        //第二種方式
        req.getRequestDispatcher("/info.jsp").forward(req, response);

beanutils封裝參數(shù)

下載
    https://commons.apache.org/proper/commons-beanutils/
    http://commons.apache.org/proper/commons-logging/ 依賴包
導(dǎo)包
  commons-beanutils-1.9.3.jar
  commons-logging-1.2.jar
頁面
    <form action="/easyuitest/one" method="post">
        用戶名:<input type="text" name="name" /><br /> 
        密碼:<input type="password" name="password" /><br /> 
        愛好: <input type="checkbox" name="hobby" value="eat" />吃 
            <input type="checkbox" name="hobby" value="sleep" />睡
            <input type="checkbox" name="hobby" value="play" />玩<br /> 
        <input type="submit" value="提交" />
    </form>
后臺工具類
    public static <T> T transform(Class clazz, HttpServletRequest req) throws Exception {
        String method = req.getMethod();
        if ("post".equalsIgnoreCase(method)) {
            req.setCharacterEncoding("UTF-8");
        }
        Object instance = null;
        instance = clazz.newInstance();
        BeanUtils.populate(instance, req.getParameterMap());
        if ("get".equalsIgnoreCase(method)) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                String name = field.getName();
                char charAt = name.charAt(0);
                String upperCase = String.valueOf(charAt).toUpperCase();
                String name2 = "set" + upperCase + name.substring(1);
                String name1 = "get" + upperCase + name.substring(1);
                Method method2 = clazz.getMethod(name2, field.getType());
                Method method3 = clazz.getMethod(name1);
                Class type = field.getType();
                Class s = String.class;
                String invoke = (String) method3.invoke(instance);
                if (s.equals(type)) {
                    invoke = new String(invoke.getBytes("iso-8859-1"), "UTF-8");
                }
                method2.invoke(instance, invoke);
            }
        }
        return (T) instance;
    }
servlet中使用
    User user = WebUtils.fillBean(request,User.class);
    System.out.println(user);
注意
    User中的屬性一定要跟jsp中的屬性一致。
原理
    private void datatoentity(HttpServletRequest request) {
        try {
            //約定:表單的每個控件name屬性值 和 需要封裝的對象的屬性名稱保持一致??!
            User user = new User();
            //獲取所有參數(shù)
            Map<String,String[]> map = request.getParameterMap();
            for(Entry<String,String[]> entry: map.entrySet()){
                //參數(shù)名稱(相當(dāng)于對象的屬性名)
                String paramName = entry.getKey();
                //參數(shù)值
                String[] paramValue = entry.getValue();
                //得到對象的屬性(Field)
                //得到類對象
                Class clazz = user.getClass();
                //獲取類的某個屬性(Field)
                Field field = clazz.getDeclaredField(paramName);
                //暴力反射
                field.setAccessible(true);
                //給屬性賦值
                //如果參數(shù)值有多個,則存入數(shù)組,否則存入數(shù)組的第一個元素
                if(paramValue.length>1){
                    //賦值
                    field.set(user, paramValue);
                }else{
                    field.set(user, paramValue[0]);
                }
            }
            System.out.println(user);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

路徑問題

瀏覽器行為   指向主機的根目錄 tomcat/webapps
服務(wù)器行為   指向當(dāng)前web應(yīng)用的根目錄  項目名稱servlettest
服務(wù)端  項目根目錄
    服務(wù)器行為
        getServletContext().getRealPath("/");
    服務(wù)器行為
        getServletContext().getResourceAsStream("/");
    服務(wù)器行為
        req.getRequestDispatcher("/");
    服務(wù)器行為  /是否開頭都一樣
        <%@ page errorPage="/" %>
    服務(wù)器行為 /是否開頭都一樣
        <%@ include file="/" %>
瀏覽器  tomcat/webapps目錄
    瀏覽器行為
        resp.sendRedirect("/");
    瀏覽器行為
        /onetest/one 絕對路徑,tomcat/webapps
        one 相對路徑,默認(rèn)是項目根目錄
        <form action="/">
    瀏覽器行為
        /onetest/two 絕對路徑,tomcat/webapps
        two 相對路徑,默認(rèn)是項目根目錄
        <a href="/" />
    瀏覽器行為
        one.css 相對路徑 
        /onetest/one.css 絕對路徑 
        <link rel="stylesheet" type="text/css" href="/" />
    瀏覽器行為
        /onetest/info.js 絕對路徑      
        info.js 相對路徑,可以這樣寫,根目錄就是項目 目錄
        <script type="text/javascript" src="/"></script>
    瀏覽器行為-超鏈接 
        response.getWriter().write("<a href='/項目名/路徑'>超鏈接</a>");
    瀏覽器行為-表單
        response.getWriter().write("<form action='/項目名/路徑'></form>");

會話管理

概述
    好比是一次通話。從打開瀏覽器,訪問多次服務(wù)器資源,關(guān)閉瀏覽器,這個過程就一次會話。
    是客戶與Web服務(wù)器間一連串的交互過程。
    會話管理就是解決多個請求數(shù)據(jù)共享的問題。
        例如:多個用戶使用瀏覽器與服務(wù)器進(jìn)行會話的過程中,服務(wù)器怎樣會每個用戶保存這些數(shù)據(jù)。
兩種技術(shù)
    Cookie技術(shù):客戶端技術(shù),數(shù)據(jù)是保存在瀏覽器的緩存中
        定義:Cookie是一些數(shù)據(jù),從Servlet發(fā)給瀏覽器,在瀏覽器中保存,然后通過瀏覽器發(fā)回給服務(wù)器。
        屬性:
            name : cookie的名稱
            value : cookie的數(shù)據(jù)
            comment : 注釋
            path : 保存的路徑
            domain : 保存的主機
            maxAge : cookie存活的時間
                負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
                正數(shù):Cookie存活在緩存文件中,只有刪除緩存文件Cookie才會丟失。
                零  :立即過期,用于刪除同名的Cookie
            version : cookie的版本
        servlet方法
            添加 addCookie()
            接收 getCookies()
        限制
            1)類型必須是字符串
            2)cookie的長度不能超過4k,一個網(wǎng)站1次只能最多發(fā)20個,所有網(wǎng)站一共發(fā)300個
            3)數(shù)據(jù)保存瀏覽器,安全性差
        優(yōu)點
            利用瀏覽器資源,減輕服務(wù)器壓力
    HttpSession技術(shù):服務(wù)器端技術(shù),數(shù)據(jù)時保存在服務(wù)器內(nèi)存中的
        是一個域?qū)ο?        獲取方式
            HttpSession session = request.getSession();
        常用方法
            setAttribute(key,value)
            getAttribute(key)
        特點
            增加服務(wù)器壓力
            任意數(shù)據(jù)類型
            大小沒有限制
            相對安全

Cookie

創(chuàng)建Cookie
    Cookie cookie = new Cookie("name","shuaige");
    /*
     * 設(shè)置Cookie存活時間
     * 負(fù)數(shù):Cookie存活在瀏覽器內(nèi)存,瀏覽器關(guān)閉Cookie丟失
     * 正數(shù):Cookie存活在緩存文件中,只有刪除緩存文件Cookie才會丟失。
     * 零  :立即過期,用于刪除同名的Cookie
     * */
    cookie.setMaxAge(Integer.MAX_VALUE);
    //默認(rèn)路徑 /項目名
    cookie.setPath("/servlet/servlettest");
    //發(fā)送給瀏覽器
    response.addCookie(cookie);
每次瀏覽器請求會默認(rèn)帶著Cookie
    //接收Cookie
    //注意什么情況可以取出Cookie發(fā)送到服務(wù)器?  獲取Cookie路徑.startWith(Cookie的保存路徑)=true的情況下可以獲取。
    //注意:如果把Cookie的保存路徑設(shè)置為當(dāng)前Web應(yīng)用的根目錄,那么在當(dāng)前web應(yīng)用下所有訪問資源時都能取出該Cookie
    Cookie[] cookies = request.getCookies();
    for(int i = 0;i<cookies.length;i++){
        Cookie cookie1 = cookies[i];
        System.out.println(cookie1);
    }
獲取用戶上次訪問的時間

用Cookie來記錄瀏覽過的商品


domain表示的是cookie所在的域,默認(rèn)為請求的地址
    同域訪問
        http://bbs.shuaige.com/onttest/one的默認(rèn)域名是bbs.shuaige.com
    跨域訪問
        http://bbs.shuaige.com/onttest/one
        http://aas.shuaige.com/onetest/one
        設(shè)置domain為.shuaige.com就可以跨域訪問了。
        本域設(shè)置不可以訪問的
        例如http://bbs.shuaige.com/onttest/one設(shè)置不可以訪問,并且http://aas.shuaige.com/onetest/one可以訪問的
        設(shè)置domain為aas.shuaige.com就可以跨域訪問了。
        path是cookie所在目錄
        瀏覽器會將domain和path都相同的cookie保存在一個文件里,cookie間用*隔開

HttpSession

存值
    //獲取session
    HttpSession session = request.getSession();
    //把數(shù)據(jù)存到session中
    session.setAttribute("name", "shuaige");    
取值
    //獲取session
    HttpSession session = request.getSession();
    //把數(shù)據(jù)從session中取出
    String name = (String)session.getAttribute("name");
    System.out.println(name);
request.getSession()方法
    1.查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
        有:返回對應(yīng)的對象
        沒有:創(chuàng)建一個新的對象返回
    2.HttpSession對象會設(shè)置一個對應(yīng)瀏覽器的JSESSINOID,通過請求頭(set-cookie)實現(xiàn)。
        HttpSession session = request.getSession();
        String sid = session.getId();
        服務(wù)器也是根據(jù)這個JSESSINOID來取出對應(yīng)的session
    3.注意:
        request.getSession(true)/request.getSession()
            查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
                有:返回對應(yīng)的對象
                沒有:創(chuàng)建一個新的對象返回
        request.getSession(false)
            查詢服務(wù)器中是否存在對應(yīng)的HttpSession對象
                有:返回對應(yīng)的對象
                沒有:返回null
原理
    HttpSession對象會設(shè)置一個對應(yīng)瀏覽器的JSESSINOID,通過請求頭(set-cookie)實現(xiàn)。
        HttpSession session = request.getSession();
        String sid = session.getId();
        服務(wù)器也是根據(jù)這個JSESSINOID來取出對應(yīng)的session
購物車

會員登錄

HttpSession鈍化與激活
    正常關(guān)閉服務(wù)
    HttpSession對象過久沒有訪問

第三方控件-上傳

概述
    由非軟件提供商提供的功能組件
    commons-fileupload文件上傳組件
        Apache提供的實現(xiàn)文件上傳的組件
        免費的、開源的
commons-fileupload API
    FileItemFactory接口
        用于構(gòu)建FileItem實例
    DiskFileItemFactory類
        是FileItemFactory接口實現(xiàn)類
        FileItemFactory  factory = new DiskFileItemFactory();
    ServletFileUpload類
        組件的核心類
        封裝表單元素并以集合方式返回
        ServletFileUpload(FileItemFactory  fileitemfactory)
        boolean isMultipartContent (HttpServletRequest request)
            靜態(tài)方法。用于判斷請求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型。是返回true,否返回false
        List parseRequest(HttpServletRequest request)
            將請求數(shù)據(jù)中的每一個字段,單獨封裝成FileItem對象,并以List方式返回
    FileItem類
        封裝表單元素的數(shù)據(jù)
        具有對表單內(nèi)容處理的方法
        常用方法
            String getFieldName() 返回表單字段元素的name屬性值
            boolean isFormField() 判斷FileItem封裝的數(shù)據(jù)是屬于普通表單字段,或者是文件表單字段。普通表單字段:true,文件表單字段:false。
            String getName() 返回上傳文件字段中的文件名,文件名通常是不含路徑信息的,取決于瀏覽器實現(xiàn)
            void write(File file) 將FileItem對象中的內(nèi)容保存到指定文件中
            String getString() 按照默認(rèn)編碼格式返回字符串
            String getString(String encoding) 按照指定編碼格式將內(nèi)容轉(zhuǎn)換成字符串返回
使用步驟
    1.獲取commons-fileupload組件
        commons-fileupload-版本號.jar
        commons-io-版本號.jar
    2.導(dǎo)入jar包
    3.設(shè)置表單提交屬性
        <form  name="form1"  method="post" enctype="multipart/form-data" />
    4.實現(xiàn)Servlet中的上傳
        4.1判斷請求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型ServletFileUpload.isMultipartContent(req)
        4.2創(chuàng)建FileItemFactory實例new DiskFileItemFactory()
        4.3創(chuàng)建ServletFileUpload實例new ServletFileUpload(factory)
        4.4解析request請求,獲取表單元素對應(yīng)的FileItem集合upload.parseRequest(req)
        4.5循環(huán)遍歷獲取數(shù)據(jù)
        4.6判斷元素類型,true-普通表單元素,false-文件元素item.isFormField()
        4.7如果是文件元素
            4.7.1獲取文件名稱item.getName()
            4.7.2如果有名稱亂碼就處理亂碼new String(name.getBytes("GBK"),"UTF-8")
            4.7.3寫出到指定位置item.write(file)
    代碼
        <form action="one" enctype="multipart/form-data" method="post">
            <input name="username" type="text"/>
            <input name="file" type="file" />
            <input type="submit" value="提交">
        </form>
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            boolean isMultipart = ServletFileUpload.isMultipartContent(req);
            if(isMultipart){
                //創(chuàng)建FileItemFactory實例
                //參數(shù)一:代表緩存大小。假如設(shè)置的大小是1M,如果上傳的文件不超過1M,那么不用緩存,如果超過1M,就使用緩存
                //參數(shù)二:代表緩存的目錄。
                //DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
                FileItemFactory factory = new DiskFileItemFactory();
                //創(chuàng)建ServletFileUpload實例
                ServletFileUpload upload = new ServletFileUpload(factory);
                try {
                    //限制文件大?。ㄏ拗茊蝹€文件不超過200KB,總文件大小不超過500KB)
                    //upload.setFileSizeMax(200*1024);//限制單個文件不超過200KB
                    //upload.setSizeMax(500*1024);//總文件大小不超過500KB
                    List<FileItem> list = upload.parseRequest(req);
                    for(FileItem item : list){
                        if(!item.isFormField()){
                            
                            //限制文件類型(只能上傳圖片文件)  mime類型: text/plain image/*
                            String contentType = item.getContentType();
                            if(!contentType.matches("image/[a-zA-Z]+")){
                                request.setAttribute("msg", "只允許上傳圖片格式的文件!");
                                request.getRequestDispatcher("/upload4.jsp").forward(request, response);
                                return;
                            }
                        
                            String name = item.getName();
                            name = new String(name.getBytes("GBK"),"UTF-8");
                            String savePath = "f:\\"+name;
                            File file = new File(savePath);
                            item.write(file);
                        }else{
                            System.out.println("表單元素:"+item.getFieldName()+"-"+item.getString());
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

分頁

優(yōu)勢
    數(shù)據(jù)能夠按照指定格式顯示,布局清晰
    不受信息數(shù)量的限制
不足
    當(dāng)數(shù)據(jù)量較多,頁面顯示不完全時,需要用戶拖動頁面才能瀏覽更多信息
實現(xiàn)
    Dao中
        1.獲取表中數(shù)據(jù)總條數(shù) int getCount();
        2.獲取指定顯示的條目 List<User> getUser(int start,int count);
    Service中
        1.每頁顯示條目個數(shù)
            int pagenum = 6;
        2.計算頁數(shù)int getTotalPageCount()
            public int getTotalPageCount(){
                int count = getCount();
                int num = count / pagenum;
                if(count%pagenum != 0){
                    num = num+1;
                }
                return num;
            }
        3.獲取指定顯示的條目
            public List<User> getUsers(int pageIndex){
                int start = (pageIndex-1)*pagenum;
                List<User> user = userDao.getUser(start, pagenum);
                return user;
            }
    Controller中
        1.獲取頁面總條目
            String totalPageCountStr = req.getParameter("totalPageCount");
            int totalPageCount = 0;
            if(totalPageCountStr != null){
                totalPageCount = Integer.valueOf(totalPageCountStr);
            }else{
                totalPageCount = service.getTotalPageCount();
            }
        2.獲取當(dāng)前顯示多少頁
            String pageIndexStr = req.getParameter("pageIndex");
            int pageIndex = 1;
            if(pageIndexStr != null){
                pageIndex = Integer.valueOf(pageIndexStr);
            }
        3.獲取需要顯示的數(shù)據(jù)
            List<User> users = service.getUsers(pageIndex);
        4.設(shè)置返回參數(shù)
            req.setAttribute("pageIndex", pageIndex);
            req.setAttribute("totalPageCount", totalPageCount);
            req.setAttribute("users",users);
    jsp中
        顯示數(shù)據(jù)
            <table border="1">
                <tr>
                    <th>id</th>
                    <th>name</th>
                    <th>age</th>
                </tr>
                <c:forEach items="${users}" var="user">
                    <tr>
                        <td>${user.id }</td>
                        <td>${user.name }</td>
                        <td>${user.age }</td>
                    </tr>
                </c:forEach>
            </table>
        顯示所有頁數(shù)的鏈接
            <% 
                int totalPageCount = (Integer)request.getAttribute("totalPageCount");
                int pageIndex = (Integer)request.getAttribute("pageIndex");
                for(int i = 1;i<=totalPageCount;i++){
                    StringBuffer sb = new StringBuffer();
                    if(i == pageIndex){
                        sb.append("<a style='padding: 5px;'>");
                    }else{
                        sb.append("<a href='one?pageIndex=");
                        sb.append(i);
                        sb.append("&totalPageCount=");
                        sb.append(totalPageCount);
                        sb.append("' style='padding: 5px;'>");
                    }
                    sb.append(i);
                    sb.append("</a>");
                    out.write(sb.toString());
                }
            %>

Servlet注解配置

@WebServlet("/login")

手動文件上傳

//1)讀取請求正文
InputStream in = request.getInputStream();
//2)轉(zhuǎn)換為字符讀取流
BufferedReader br = new BufferedReader(new InputStreamReader(in));
//3)第一行:讀取文件的分割符
String fileTag = br.readLine();
//4)第二行:讀取文件名稱
String line = br.readLine();
String fileName = line.substring( line.lastIndexOf("filename=\"")+10 , line.length()-1);
//跳過兩行
br.readLine();
br.readLine();
//5)讀取文件內(nèi)容
String str = null;
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\targetFiles\\"+fileName));
//不斷讀取
while(  (str=br.readLine())!=null ){
    //忽略文件的分割符
    if( (fileTag+"--").equals(str)){
        break;
    }
    bw.write(str);//寫出一行
    bw.newLine();//換行符
}
bw.close();
br.close();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容