Servlet

Servlet介紹

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

Servlet開發(fā)步驟

1)java類删掀,繼承HttpServlet類
    覆蓋doGet和doPost方法
2)在web應(yīng)用web.xml中配置servlet
3)請(qǐng)求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ǔ)上擴(kuò)展了Http協(xié)議的Servlet
    //會(huì)先調(diào)用service方法,然后根據(jù)請(qǐng)求方式來進(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披泪,相對(duì)于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 {
    //這個(gè)super一定不要?jiǎng)h掉
    super.init(config);
    //通過ServletConfig對(duì)象讀取初始化參數(shù)
    String initParameter = config.getInitParameter("initParam");
    System.out.println(initParameter);
    //獲得所有參數(shù)的key
    Enumeration<String> enumeration = config.getInitParameterNames();
}
有參的init 與 無參init
    有參init:生命周期方法纤子,必定會(huì)被服務(wù)器調(diào)用。(內(nèi)部默認(rèn)會(huì)調(diào)用無參的init方法)
    無參init:提供給開發(fā)者進(jìn)行初始化工作的方法付呕。

Servlet生命周期

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

Servlet線程安全問題

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

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

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

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

ServletConfig對(duì)象

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

ServletContext對(duì)象

概述
    ServletContext是servlet的上下文對(duì)象沾谜。
    代表當(dāng)前web應(yīng)用。
    一個(gè)web有且只有一個(gè)ServletContext對(duì)象胀莹。
獲取ServletContext對(duì)象
    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();
        //獲取一個(gè)文件的絕對(duì)路徑 - 獲取的項(xiàng)目根目錄
        //要以/開頭
        String realPath = servletContext.getRealPath("/");
        System.out.println(realPath);
        //讀取一個(gè)文件基跑,并且返回一個(gè)文件流
        InputStream inputStream = servletContext.getResourceAsStream("/路徑");

HttpServletResponse對(duì)象

response對(duì)象
    表示響應(yīng)對(duì)象,包含所有的響應(yīng)數(shù)據(jù)描焰。使用response對(duì)象可以修改響應(yīng)數(shù)據(jù)媳否。
響應(yīng)格式
    響應(yīng)行
        http版本
        狀態(tài)碼 setStatus(sc)方法
        描述
    響應(yīng)頭
        鍵值對(duì) 
            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ù)器- 這個(gè)代碼可以省略
            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ù)器之間請(qǐng)求頭和響應(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();
輸出隨機(jī)驗(yàn)證碼(防止惡意注冊(cè)和登錄)
    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è)置隨機(jī)干擾線
        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);
            //隨機(jī)色
            graphics.setColor(getRanColor());
            graphics.drawLine(x1, y1, x2, y2);
        }
        //把這個(gè)圖片寫出給瀏覽器
        ServletOutputStream outputStream = response.getOutputStream();
        ImageIO.write(image, "gif", outputStream);
    }
    //獲取隨機(jī)顏色
    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ā)出兩次請(qǐng)求
    地址欄會(huì)發(fā)生變化
    可以重定向任何資源(包括應(yīng)用外的資源)
    不可以通過request來共享數(shù)據(jù)
    代碼
        response.sendRedirect("/info.jsp");

HttpServletRequest對(duì)象

概述
    表示請(qǐng)求對(duì)象,包含所有的請(qǐng)求數(shù)據(jù)室抽。使用request獲取請(qǐng)求的數(shù)據(jù)搪哪。
請(qǐng)求格式
    請(qǐng)求行
        請(qǐng)求方式  request.getMethod()
        請(qǐng)求資源  request.getRequestURL() / request.getRequestURI()
        http版本  request.getProtocol()
        獲得get請(qǐng)求的參數(shù) request.getQueryString()
    請(qǐng)求頭
        獲得一個(gè)請(qǐng)求頭 getHeader(key) 
        獲得整形的請(qǐng)求頭 getIntHeader(key) 
        獲得日期類型的請(qǐng)求頭 getDateHeader(key) 
    空行
    正文
        獲得正文 getInputStream()
防盜鏈
    String referer = request.getHeader("referer");
    if(referer == null || !referer.contains("/servlettest")){
        //非法連接
        return;
    }
獲取表單數(shù)據(jù)
    get : getQueryString()
    post : getInputStream()
    通用方式 
        獲取某個(gè)參數(shù) getParameter("")
        獲取某個(gè)參數(shù)的集合 getParameterValues("") 例如:checkbox
        獲取所有的參數(shù)名 getParameterNames()
        獲取所有的參數(shù) getParameterMap()
亂碼問題
    if("post".equalsIgnoreCase(request.getMethod())){
        //只能解決post提交的參數(shù),不能解決get提交的參數(shù)坪圾,因?yàn)檫@個(gè)方法只能設(shè)置請(qǐng)求正文的內(nèi)容
        request.setCharacterEncoding("UTF-8");
    }
    String name = request.getParameter("name");//默認(rèn)是iso-8859-1
    if("get".equalsIgnoreCase(request.getMethod())){
        //get請(qǐng)求的參數(shù)需要手動(dòng)解碼
        name = new String(name.getBytes("iso-8859-1"),"UTF-8");
    }
轉(zhuǎn)發(fā)
    發(fā)出一次請(qǐng)求
    地址欄不會(huì)發(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>
后臺(tái)工具類
    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 {
            //約定:表單的每個(gè)控件name屬性值 和 需要封裝的對(duì)象的屬性名稱保持一致!兽泄!
            User user = new User();
            //獲取所有參數(shù)
            Map<String,String[]> map = request.getParameterMap();
            for(Entry<String,String[]> entry: map.entrySet()){
                //參數(shù)名稱(相當(dāng)于對(duì)象的屬性名)
                String paramName = entry.getKey();
                //參數(shù)值
                String[] paramValue = entry.getValue();
                //得到對(duì)象的屬性(Field)
                //得到類對(duì)象
                Class clazz = user.getClass();
                //獲取類的某個(gè)屬性(Field)
                Field field = clazz.getDeclaredField(paramName);
                //暴力反射
                field.setAccessible(true);
                //給屬性賦值
                //如果參數(shù)值有多個(gè)漓概,則存入數(shù)組,否則存入數(shù)組的第一個(gè)元素
                if(paramValue.length>1){
                    //賦值
                    field.set(user, paramValue);
                }else{
                    field.set(user, paramValue[0]);
                }
            }
            System.out.println(user);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

路徑問題

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

會(huì)話管理

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

Cookie

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

用Cookie來記錄瀏覽過的商品


domain表示的是cookie所在的域劳淆,默認(rèn)為請(qǐng)求的地址
    同域訪問
        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所在目錄
        瀏覽器會(huì)將domain和path都相同的cookie保存在一個(gè)文件里括勺,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ù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
        有:返回對(duì)應(yīng)的對(duì)象
        沒有:創(chuàng)建一個(gè)新的對(duì)象返回
    2.HttpSession對(duì)象會(huì)設(shè)置一個(gè)對(duì)應(yīng)瀏覽器的JSESSINOID,通過請(qǐng)求頭(set-cookie)實(shí)現(xiàn)。
        HttpSession session = request.getSession();
        String sid = session.getId();
        服務(wù)器也是根據(jù)這個(gè)JSESSINOID來取出對(duì)應(yīng)的session
    3.注意:
        request.getSession(true)/request.getSession()
            查詢服務(wù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
                有:返回對(duì)應(yīng)的對(duì)象
                沒有:創(chuàng)建一個(gè)新的對(duì)象返回
        request.getSession(false)
            查詢服務(wù)器中是否存在對(duì)應(yīng)的HttpSession對(duì)象
                有:返回對(duì)應(yīng)的對(duì)象
                沒有:返回null
原理
    HttpSession對(duì)象會(huì)設(shè)置一個(gè)對(duì)應(yīng)瀏覽器的JSESSINOID,通過請(qǐng)求頭(set-cookie)實(shí)現(xiàn)曲掰。
        HttpSession session = request.getSession();
        String sid = session.getId();
        服務(wù)器也是根據(jù)這個(gè)JSESSINOID來取出對(duì)應(yīng)的session
購物車

會(huì)員登錄

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

第三方控件-上傳

概述
    由非軟件提供商提供的功能組件
    commons-fileupload文件上傳組件
        Apache提供的實(shí)現(xiàn)文件上傳的組件
        免費(fèi)的疾捍、開源的
commons-fileupload API
    FileItemFactory接口
        用于構(gòu)建FileItem實(shí)例
    DiskFileItemFactory類
        是FileItemFactory接口實(shí)現(xiàn)類
        FileItemFactory  factory = new DiskFileItemFactory();
    ServletFileUpload類
        組件的核心類
        封裝表單元素并以集合方式返回
        ServletFileUpload(FileItemFactory  fileitemfactory)
        boolean isMultipartContent (HttpServletRequest request)
            靜態(tài)方法。用于判斷請(qǐng)求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型栏妖。是返回true乱豆,否返回false
        List parseRequest(HttpServletRequest request)
            將請(qǐng)求數(shù)據(jù)中的每一個(gè)字段,單獨(dú)封裝成FileItem對(duì)象底哥,并以List方式返回
    FileItem類
        封裝表單元素的數(shù)據(jù)
        具有對(duì)表單內(nèi)容處理的方法
        常用方法
            String getFieldName() 返回表單字段元素的name屬性值
            boolean isFormField() 判斷FileItem封裝的數(shù)據(jù)是屬于普通表單字段咙鞍,或者是文件表單字段。普通表單字段:true趾徽,文件表單字段:false续滋。
            String getName() 返回上傳文件字段中的文件名,文件名通常是不含路徑信息的孵奶,取決于瀏覽器實(shí)現(xiàn)
            void write(File file) 將FileItem對(duì)象中的內(nèi)容保存到指定文件中
            String getString() 按照默認(rèn)編碼格式返回字符串
            String getString(String encoding) 按照指定編碼格式將內(nèi)容轉(zhuǎn)換成字符串返回
使用步驟
    1.獲取commons-fileupload組件
        commons-fileupload-版本號(hào).jar
        commons-io-版本號(hào).jar
    2.導(dǎo)入jar包
    3.設(shè)置表單提交屬性
        <form  name="form1"  method="post" enctype="multipart/form-data" />
    4.實(shí)現(xiàn)Servlet中的上傳
        4.1判斷請(qǐng)求數(shù)據(jù)中的內(nèi)容是否是multipart/form-data類型ServletFileUpload.isMultipartContent(req)
        4.2創(chuàng)建FileItemFactory實(shí)例new DiskFileItemFactory()
        4.3創(chuàng)建ServletFileUpload實(shí)例new ServletFileUpload(factory)
        4.4解析request請(qǐng)求,獲取表單元素對(duì)應(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ù)一:代表緩存大小疲酌。假如設(shè)置的大小是1M,如果上傳的文件不超過1M了袁,那么不用緩存朗恳,如果超過1M,就使用緩存
                //參數(shù)二:代表緩存的目錄载绿。
                //DiskFileItemFactory factory = new DiskFileItemFactory(1024*1024,new File("C:\\tempFiles"));
                FileItemFactory factory = new DiskFileItemFactory();
                //創(chuàng)建ServletFileUpload實(shí)例
                ServletFileUpload upload = new ServletFileUpload(factory);
                try {
                    //限制文件大兄嘟搿(限制單個(gè)文件不超過200KB,總文件大小不超過500KB)
                    //upload.setFileSizeMax(200*1024);//限制單個(gè)文件不超過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ù)量較多怀浆,頁面顯示不完全時(shí)谊囚,需要用戶拖動(dòng)頁面才能瀏覽更多信息
實(shí)現(xiàn)
    Dao中
        1.獲取表中數(shù)據(jù)總條數(shù) int getCount();
        2.獲取指定顯示的條目 List<User> getUser(int start,int count);
    Service中
        1.每頁顯示條目個(gè)數(shù)
            int pagenum = 6;
        2.計(jì)算頁數(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")

手動(dòng)文件上傳

//1)讀取請(qǐng)求正文
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)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市执赡,隨后出現(xiàn)的幾起案子镰踏,更是在濱河造成了極大的恐慌,老刑警劉巖沙合,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奠伪,死亡現(xiàn)場離奇詭異,居然都是意外死亡首懈,警方通過查閱死者的電腦和手機(jī)绊率,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來猜拾,“玉大人即舌,你說我怎么就攤上這事】嫱啵” “怎么了顽聂?”我有些...
    開封第一講書人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盯仪。 經(jīng)常有香客問我紊搪,道長,這世上最難降的妖魔是什么全景? 我笑而不...
    開封第一講書人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任耀石,我火速辦了婚禮,結(jié)果婚禮上爸黄,老公的妹妹穿的比我還像新娘滞伟。我一直安慰自己,他們只是感情好炕贵,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開白布梆奈。 她就那樣靜靜地躺著,像睡著了一般称开。 火紅的嫁衣襯著肌膚如雪亩钟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,874評(píng)論 1 314
  • 那天鳖轰,我揣著相機(jī)與錄音清酥,去河邊找鬼。 笑死蕴侣,一個(gè)胖子當(dāng)著我的面吹牛焰轻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昆雀,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼鹦马,長吁一口氣:“原來是場噩夢啊……” “哼胧谈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起荸频,我...
    開封第一講書人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎客冈,沒想到半個(gè)月后旭从,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡场仲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年和悦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片渠缕。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鸽素,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出亦鳞,到底是詐尸還是另有隱情馍忽,我是刑警寧澤,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布燕差,位于F島的核電站遭笋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏徒探。R本人自食惡果不足惜瓦呼,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望测暗。 院中可真熱鬧央串,春花似錦、人聲如沸碗啄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽挫掏。三九已至侦另,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尉共,已是汗流浹背褒傅。 一陣腳步聲響...
    開封第一講書人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袄友,地道東北人殿托。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像剧蚣,于是被迫代替她去往敵國和親支竹。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旋廷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容