Servlet-JSP

Servlet概述
    servlet是java编写的服务器端程序
    servlet就是直接或间接实现javax.servlet.Servlet接口的一个类
    servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。
    注意:tomcat 实现servlet和JSP,具有servlet和JSP的接口,如果需要源码,使用tomcat的源码即可



Servlet编写流程
    1. 创建一个类并实现相关接口或继承相关类(Servlet接口,GenericServlet类,HttpServlet类)
    2. 在web.xml中配置
        <servlet>
            <servlet-name> 随便起个名,注意不要重复,一般为类名
            <servlet-class> servlet的全限定名
        </servlet>
        <servlet-mapping>
            <servlet-name> 上面的servlet-name
            <url-pattern> 以/开头,如/demo
        </servlet-mapping>
    3. 访问路径 http://localhost:8080/项目名 + url-pattern的值



Servlet接口(javax.servlet)
    定义所有 servlet 都必须实现的方法。
    方法:
        destroy()销毁方法
        getServletConfig() 返回ServletConfig对象,包含servlet的初始化参数信息
        getServletInfo()  返回有关 servlet 的信息,比如作者、版本和版权。
        init(ServletConfig) 初始化方法
        service(ServletRequest,ServletResponse) 每次请求的执行方法



Servlet生命周期
    init(ServletConfig) 初始化方法
    service(ServletRequest,ServletRepsonse) 每次请求的执行方法
    destroy() 销毁方法



init方法
    初始化方法
    调用者:tomcat (web服务器,web容器,servlet容器)
    执行次数:1次
    执行时间:
        默认情况:第一次请求的开始,肯定在service方法之前
        手动配置,在服务器启动时执行,在web.xml中配置
        例:
            <servlet>
                <servlet-name>
                <servlet-class>
                <load-on-startup>0</load-on-startup>
            </servlet>
            配置当前 servlet在服务器启动时执行init方法
            取值:整型,(0 - 7)数字越小,优先级越高 
    参数
        ServletConfig 对象,当前Servlet配置描述对象
            接口:javax.servlet.ServletConfig
            实现类:tomcat实现类,org.apache.catalina.core.StandardWrapperFacade
            常用方法
                获得servlet配置名称, web.xml <servlet><servlet-name>
                    config.getServletName()
                通过名称获得当前servlet的初始化参数的值,如果名称不存在返回null
                    config.getInitParameter("username")
                获得当前servlet的所有初始化参数的名称
                    config.getInitParameterNames()
                    例:
                    Enumeration<String> allName = config.getInitParameterNames();
                    while(allName.hasMoreElements()){
                        String name = allName.nextElement();
                        String value = config.getInitParameter(name);
                        System.out.println("all --> " + name + " : "  + value);
                    }
                获得ServletContext对象
                    config.getServletContext();



service方法
    每次请求的执行方法
    调用者:tomcat
    执行次数:每请求一次执行一次
    执行时间:请求时
    参数
        ServletRequest 对象
            接口:javax.servlet.ServletRequest
            实现类:org.apache.catalina.connector.RequestFacade
            RequestFacade 实现了 HttpServletRequest接口, HttpServletRequest接口 继承了 ServletRequest接口
            所以可以
                HttpServletRequest request = (HttpServletRequest) req;
        ServletResponse对象
            接口:javax.servlet.ServletResponse
            实现类:org.apache.catalina.connector.ResponseFacade
            ResponseFacade 实现了 HttpServletResponse接口, HttpServletResponse接口 继承了 ServletResponse
            所以可以
                HttpServletResponse response = (HttpServletResponse) res;
    结论
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;



destroy方法
    销毁方法
    调用者:tomcat
    执行次数:1次
    执行时间:tomcat正常关闭



GenericServlet类
    继承Servlet接口需要实现5个方法,但有的方法不需要
    所以可以继承GenericServlet类,必须实现的方法只有service方法,其它方法按需要重写
    抽象方法: service方法
    注意:
        需要重写初始化方法时,不要重写init(ServletConfig),要重写init()方法
        因为GenericServlet类对参数进行了缓存(this.config = config),提供了一些便捷方法.如果重写了,也没有调用父类的方法,则如果别的地方使用了便捷方法会报错
            GenericServlet类的init(ServletConfig)会自动调用init()方法
            参数可以通过GenericServlet类的getServletConfig()方法获得
    便捷方法:
        可以直接用servlet对象调用getInitParameter和getServletContext方法(本来是ServletConfig类的方法)
    此类是通用servlet实现类,与协议无关。



HttpServlet类
    与HTTP协议有关的servlet实现。
    HttpServlet 将service 方法 进行分流,分成了7种。根据不同的请求方式分别调用不同的方法
        底层;HttpServletRequest.getMethod()获得请求方式:返回值POST | GET等
    继承HttpServlet,并覆写doGet、doPost分别用于处理get请求和post 请求



Servlet访问路径配置
    即<url-pattern>的值
    1 完全匹配路径
        例如:/page/oneServlet
    2 不完全匹配路径(通配符匹配*)
        例如:/page/*           --> page目录所有路径
        例如:/*                --> 所有路径
    3 扩展名匹配(*.xx)
        例如:*.jsp         --> 所有的jsp文件
        例如:*.html            --> 所有的html文件
    总结,访问优先级:完全匹配路径  >  通配符匹配  > 扩展名匹配  > 缺省servlet/
        缺省servlet就是访问路径为/的servlet,当没有匹配上任何路径的时候,会执行缺省servlet.
        一般不要配置缺省servlet,tomcat有默认实现.
        即 获得请求路径(如/abc/123.html),读取相应文件,将文件发送给浏览器.如果没有读到文件,会返回404
        浏览器是不能访问服务器本地文件的,都是通过缺省servlet返回资源的



配置Servlet的初始化参数
    在web.xml中<servlet>中的<servlet-class>后添加<init-param>
    例:
        <servlet>
            <servlet-name>
            <servlet-class>
            <init-param>
                <param-name>参数名</param-name>
                <param-value>参数值</param-value>
            </init-param>
        </servlet>



修改myeclipse的servlet模板
    0 关闭myeclipse
    1 查询myeclipse common目录
        myeclipse安装,查看myeclipse.ini,通过第四行确定common目录的位置
    2 查找文件,Common/plugins/com.genuitec.eclipse.wizards_*.jar
    3 修改jar中的templates/Servlet.java文件(注意备份)
        如:
            <aw:method name="doGet">
                public void doGet(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                    this.doPost(request, response);
                }
            </aw:method>

            <aw:method name="doPost">
                public void doPost(HttpServletRequest request, HttpServletResponse response)
                        throws ServletException, IOException {
                    request.setCharacterEncoding("utf-8");
                    
                }
            </aw:method>



ServletContext类
    Servlet上下文对象。Servlet管理者
        此对象由tomcat在启动时创建,每一个web项目都对应一个ServletContext对象实例
        Tomcat关闭时将释放资源--在tomcat启动之后一直存在于内存中。
    获得方式
        1 在servlet的doGet、doPost方法中使用 
            this.getServletConfig().getServletContext 或 this.getServletContext()
        2 Servlet3.0 ServletRequest提供相应的方法 (了解)
            request.getServletContext()
    常用方法
        1 属性操作(内存管理) --xxxAttribute
            setAttribute(String name,Object value) ,给一个对象进行名称,并放入到内存中。
            Object getAttribute(String name) ,通过给定的名称获得对象,如果没有获得数据返回null
            removeAttribute(String name)  ,通过给定的名称移除对象
            在多个servlet之间进行数据共享。因为服务器关闭时才释放资源,不建议将经常修改的内容放置此处。
        2 管理资源
            String getRealPath(java.lang.String path) 获得发布到tomcat下web项目中的文件的具体位置(绝对路径)
                例如:getRealPath("/WEB-INF/web.xml")  --> D:\java\tomcat\apache-tomcat-7.0.42\webapps\day04_demo\WEB-INF\web.xml
            InputStream getResourceAsStream(java.lang.String path) 获得发布到tomcat下web项目中的文件的资源流
            Set<String> getResourcePaths(java.lang.String path) 获得指定目录下面的所有文件或目录的相对路径,返回Set集合
            以上三个方法,参数都是以项目文件夹为根的相对路径
        3 获取web项目的初始化参数
            getInitParameter(java.lang.String name) 获得整个web项目的指定名称的初始化参数
            getInitParameterNames() 获得整个web项目所有的初始化参数的名称



配置web项目的初始化参数
    在根标签<web-app>下添加<context-param>标签
    例:
        <context-param>
            <param-name>参数名</param-name>
            <param-value>参数值</param-value>
        </context-param>



Servlet执行流程(单实例)
    单实例,多线程
    单实例,可能存在线程并发访问问题。尽量避免使用成员变量



MyEclipse执行可运行类的方式
    如/sss/bin/cn/itcast/Test.class
    先定位到项目根目录,然后设置classPath路径去执行
        如: F:\workspaces\sss>java -cp F:\workspaces\sss\bin cn.itcast.Test



重定向
    响应行:响应编号:302
    响应头:存在一个location头
    当浏览器接收到302后,将会向响应头中的location的值表示的路径再次发送一个请求



资源访问路径
    使用java代码访问资源
        绝对路径
        相对路径(按方法区分)
            new File(string)
                相对路径
                    不加/的相对路径:以 运行环境所在目录 为根
                    加/的相对路径:  以 运行环境所在目录的根目录 为根(即盘符的根)
                运行环境
                    在MyEclipse中运行main方法时,运行环境为 项目目录
                    在命令行窗口运行main方法时,运行环境为 classPath文件夹(一般为项目目录下的bin目录)
            Class类的getResourceAsStream方法 和 Class类的getResource方法
                    不加/的相对路径:以 类文件所在目录 为根
                    加/的相对路径:  以 classPath目录 为根
            ClassLoader类的getResourceAsStream方法(ClassLoader类的getResource方法加/的相对路径不会用)
                    不加/的相对路径:以 classPath目录 为根
                    加/的相对路径:  以 classPath目录 为根
            ServletContext类的getRealPath方法
                    不加/的相对路径:以 项目文件夹 为根
                    加/的相对路径:  以 项目文件夹 为根
            ServletContext类的getResourceAsStream方法
                    不加/的相对路径:以 项目发布文件夹 为根(对应MyEclipse中的WebRoot目录)
                    加/的相对路径:  以 项目发布文件夹 为根(对应MyEclipse中的WebRoot目录)
            HttpServletRequest类的getRequestDispatcher方法
                    不加/的相对路径:以 当前serlvet配置路径父路径 为根
                    加/的相对路径:  以 项目发布文件夹 为根(对应MyEclipse中的WebRoot目录)
            HttpServletResponse类的sendRedirect方法
                    不加/的相对路径:以 当前serlvet配置路径父路径 为根
                    加/的相对路径:  以 tomcat发布文件夹 为根(项目上一级文件夹)
        小结
            当使用相对路径时,
                获得src下的资源
                    类名.class.getResourceAsStream("/名称")
                    类名.class.getClassLoader().getResourceAsStream("名称")
                    类名.class.getClassLoader().getResourceAsStream("/名称")
                获得WebRoot下的资源
                    this.getServletContext().getResourceAsStream("名称");
                    this.getServletContext().getResourceAsStream("/名称");
                获得项目下的资源的绝对路径
                    java项目
                        类名.class.getResource("/classpath下面的资源").getPath()
                        类名.class.getResource("当前包下面的资源").getPath()
                    web项目
                        this.getServletContext().getRealPath("/项目下路径")
                当使用请求转发和重定向时,参数都要以/开头,请求转发不加项目名称,重定向前面要加项目名称
                可通过this.getClass.getResource("/").getPath()获得项目classPath的路径
    浏览器访问资源
        完整路径
        相对路径
            不以/开头:  以 当前文件所在目录 为根
            以/开头:    以 tomcat发布文件夹 为根(项目上一级文件夹)
    注意:
        相对路径中
            ./  为当前目录
            ../ 为上一层目录,可以多层嵌套使用



HttpServletResponse接口(response)
    http协议的响应描述对象
    常用方法:
        响应行
            修改状态码:setStatus(int sc) 
                HttpServletResponse 提供状态码对应常量。
                回顾:200正常、302重定向(localhost)、304未修改、404不存在、500服务器异常
        响应头
            setHeader(java.lang.String name, java.lang.String value)//设置响应头,name固定头,value响应值
            setIntHeader(java.lang.String name, int value)          //设置响应头,值为整形
            setDateHeader(java.lang.String name, long date)         //设置响应头,值为日期
            sendRedirect(String location)                           //设置重定向的便捷方法,底层setStatus(302);setHeader("location","路径");
            setContentType(java.lang.String type)                   //设置content-type的便捷方法,可用于设置编码,底层setHeader("content-type","text/html;charset=编码")
        响应体 (流)
            ServletOutputStream getOutputStream() 获得字节流
            PrintWriter getWriter() 获得字符流
            注意:
                1 如果流缓存已经被刷新(手动,自动缓存溢出8k) ,不能进行重定向。
                2 流一般不用进行手动关闭,tomcat自动进行关流。
                3 getOutputStream 和 getWriter 不能同时使用
        String encodeURL(String url);
        //如果客户端禁用cookie,则session失效
        //此方法可以把session的id添加到url后面,使服务器找到指定session
        //可在重定向或转发前处理url(在Servlet中使用前应先获取到session,否则无效)



HttpServletRequest接口(request)
    http协议的请求描述对象
    一次请求将创建一组request和response
    常用方法
        1 获得浏览器发送的请求参数的数据
            String getParameter(java.lang.String name) ,通过参数名称获取参数值
            String[] getParameterValues(java.lang.String name) ,通过参数名称获取一组值(String数组,通常用于多选框)
            Map<String,String[]> getParameterMap() 获得所有参数信息
        2 属性操作
            setAttribute / getAttribute /removeAttribute
            注意:
                属性操作是对request对象内存的操作.当进行请求转发时,parameter参数都会丢失,而request中的数据可以通过方法参数传递
                parameter参数通过字符串传递,只能传递字符串,主要用于浏览器和服务器之间的数据传输
                request是java对象,可以存任何类型的数据,用于服务器端的数据传输(请求转发或页面渲染)
        3 常用方法
            getScheme()         //获得协议
            getServerName()     //获得服务器名称(域名)
            getRemoteAddr()     //获得客户端ip
            getServerPort()     //获得服务器端口
            getContextPath()    //获得项目名称
            getServletPath()    //获得Servlet的配置路径
            getRequestURL()     //获得请求全路径
            getRequestURI()     // "/"+项目名+Servlet配置路径
            getQueryString()    //获得请求路径中?后的字符串
            getInputStream()    //获得请求体
            setCharacterEncoding(java.lang.String env) //设置post请求的中文编码
            getRequestDispatcher(String url)            //获得请求调度器,用于请求转发



中文乱码
    参数传递的不同方式
        表单提交post请求: 请求体,进行url编码
        表单提交get请求: 请求行,进行url编码
        超链接: 请求行,不进行url编码
        地址栏直接输入: 请求行,不进行url编码,但是跟操作系统默认编码有关(其它都只跟页面编码有关)
        表单的enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码,默认值为application/x-www-form-urlencoded,所以表单数据会默认进行url编码表单的enctype 
        表单使用post请求但是在请求路径后跟?加的参数 是在请求行中传递的,不会进行url编码
    url编码
        处理请求行或请求体中的数据,用于传递非标准的字母和字符
        js代码
            url编码 : 
                encodeURI(str,编码);            //不对特殊字符编码
                encodeURIComponent(str,编码);   //对特殊字符编码,如 : / & =
            url解码 : 
                decodeURI(str,编码);
                decodeURIComponent(str,编码);
        java代码
            url编码 : java.net.URLEncoder.encode(str, 编码);
            url解码 : java.net.URLDecoder.decode(str, 编码);
        url编码规则(了解):
            任何特殊的字符(就是那些不是简单的七位ASCII,如汉字)将以百分符%用十六进制编码,当然也包括象 =,&;,和 % 这些特殊的字符。
            其实url编码就是一个字符ascii码的十六进制。不过稍微有些变动,需要在前面加上“%”。
            比如“\”,它的ascii码是92,92的十六进制是5c,所以“\”的url编码就是%5c。“胡”的ascii码是-17670,十六进制是BAFA,url编码是“%BA%FA”。
        注意
            js的encodeURIComponent方法和java的encode方法效果相同
            js的两个编码方法都可以用java的decode方法解码出原来的值
            表单提交get请求进行的是encodeURI方法的编码
            下面是js的encodeURI方法进行url编码的结果示例(编码为utf-8)
                原字符串:userServlet?name=李凯昊&password=123
                编码后  :userServlet?name=%E6%9D%8E%E5%87%AF%E6%98%8A&password=123
    乱码处理(页面编码为utf-8)
        response对象
            服务器:response.setContentType("text/html;charset=UTF-8");
        表单提交post请求
            服务器:request.setCharacterEncoding("UTF-8");
                或:value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
                或:value = URLDecoder.decode(URLEncoder.encode(value,"ISO8859-1"),"UTF-8");
        表单提交get请求,post请求路径后的参数,超链接
            服务器:value = new String(value.getBytes("ISO-8859-1"),"UTF-8");
                或:value = URLDecoder.decode(URLEncoder.encode(value,"ISO8859-1"),"UTF-8");
        地址栏输入时路径后跟参数
            服务器:value = new String(value.getBytes("ISO-8859-1"),"gbk");
                或:value = URLDecoder.decode(URLEncoder.encode(value,"ISO8859-1"),"gbk");
        终极方式(不推荐使用)
            修改Tomcat配置文件conf/server.xml
            <Connector port="8080" protocol="HTTP/1.1" ... URIEncoding="UTF-8">
        还有一种可行的方式:用js控制提交数据时,可以先对数据进行两次url编码,然后在服务器接受数据时进行一次url解码即可(tomcat自动解码一次)



请求转发(forward)
    将一次请求,转发到另一个servlet进行处理。是一次请求,地址栏不改变
    RequestDispatcher 请求调度器
        获得方式:
            ServletContext.getRequestDispatcher(java.lang.String) 
            ServletRequest.getRequestDispatcher(java.lang.String) 
        方法:
            forward(ServletRequest request, ServletResponse response) 转发,可以涉及多个servlet,但浏览器只显示最后一个servlet输出内容。
            include(ServletRequest request, ServletResponse response) 包含,可以涉及多个servlet,将多个servlet输出内容合并一起输出。
    注意:
        请求转发可以使用request属性进行数据的传递
        转发之间使用的request对象是不同(类型也不一样),但数据是一致的。(底层克隆)
        转发使用的response对象是同一个对象,不过前一个Servlet在转发前输出的内容不会发送到浏览器
        当转发完成之后,需要回到转发触发的位置,继续执行程序,只是之后输出的数据不在浏览器中进行显示。



请求转发和重定向对比
    请求转发: 是一次请求,可以通过request对象传递数据,地址栏地址不改变
    重定向: 是两次请求,需要通过url传递参数,地址栏地址改变
    请求转发和重定向的路径也不一样,请求转发的以/开头的相对路径不需要加项目名,而重定向需要
    请求转发是request对象的方法,重定向是response的方法



会话概述
    一个有限时间窗口内来自同一浏览器的请求标识为一个会话。
    当一个未知的客户向Web应用程序发送第一个请求时就开始了一个会话。当客户明确结束会话(关闭浏览器)或服务器在一个预定义的时限内不从客户接受任何请求时,会话就结束了。
    会话技术
        cookie,浏览器端进行缓存数据的技术
        session,服务器端进行缓存数据的技术



cookie
    cookie 是 servlet 发送到 Web 浏览器的少量信息,这些信息由浏览器保存,然后发送回服务器。cookie 的值可以唯一地标识客户端,因此 cookie 常用于会话管理。 
    Cookie类(javax.servlet.http)
        Cookie类是对http协议cookie进行描述的类
        构造方法
            new Cookie(String name,String value)
        常用方法
            getName()       获得名称
            getValue()      获得值
            setMaxAge(秒)   设置有效时间,单位为秒,时间到自动清空,不设置的话默认会话结束自动清空.如果值为0,表示删除cookie.
            setPath("/")    设置路径,将当前cookie路径修改为web站点根目录,默认值是servlet父路径.request携带的cookie是同级或父级的,不能携带子级的cookie
    服务器发送cookie:response.addCookie(Cookie)
    获得当前request携带所有的cookie信息:request.getCookies();
    注意:
        cookie中的数据存储到客户端,可以直接看到内容,所以不安全
        浏览器只会发送cookie的name和value
        服务器设置cookie的响应头示例: Set-Cookie: 键=值
        浏览器发送cookie的响应头示例: Cookie: 键=值
        cookie不支持中文(试试url编码后再存)
    示例:
        //设置cookie
        Cookie a=new Cookie("password","123");
        a.setMaxAge(60*60*24*7);//保存一周
        a.setPath("/");//任何路径都可以访问到此cookie
        response.addCookie(a);
        //读取cookie
        Cookie []cookies=request.getCookies();
        if(cookies!=null){
            for(Cookie cookie : cookies){
                out.println(cookie.getName()+"="+cookie.getValue()+"<br>");
            }
        }
        //删除cookie
        Cookie[] cookies=request.getCookies();
        for(Cookie cookie : cookies){
            if(cookie.getName().equals("username")){
                cookie.setMaxAge(0);
            }
        }



session
    概述
        提供一种方式,跨多个页面请求或对 Web 站点的多次访问标识用户并存储有关该用户的信息。
        服务器能够以多种方式维护会话,比如使用 cookie 或重写 URL。 (自动使用cookie标识会话,当客户端禁用cookie时,可以使用重写URL的方式)
        当我们创建一个session,服务器自动创建cookie,将session的id发送给浏览器,每一次请求将session的id回传给服务器,request将通过session的id标识一个客户端。
    获得方式 
        request.getSession()    //如果服务器端没有缓存session,则创建,如果有,则获取引用
    HttpSession接口(javax.servlet.http.HttpSession)
        HttpSession类是对http协议session进行描述的类
        属性操作
            setAttribute / getAttribute /removeAttribute
            属性操作是对session对象内存的操作.可以实现在一个会话,多个请求之间存储获取数据
        常用方法
            void setMaxInactiveInterval(int time)  设置多少秒内未使用此session则删除此session
            void invalidate()  销毁session
            boolean isNew()  返回session是否是这次请求刚创建的
            getId()  返回session的标识ID
    注意:
        session默认为会话级别,即浏览器退出session失效,可通过setMaxInactiveInterval手动设置时间
        默认情况下,每次请求会携带cookie:jsessionid:"sessionid的值",服务器根据sessionid值确定session
    session对象的销毁
        1.过期了,默认值30分钟(可在web.xml中设置<session-config>)或setMaxInactiveInterval方法设置时间到期
        2.执行session.invalidate()直接销毁
        3.服务器非正常关闭。(正常关闭,会对session进行持久化存储,启动时再读取)
    重写URL
        如果客户端禁用cookie,则session失效,可使用重写url维护session.
        会将session的id通过url回传给服务器,例:http://localhost:8080/day06/sessionAttribute2Servlet;jsessionid=B2AC41059935320C52B41808DB651A09
        response的方法:
            encodeURL(java.lang.String url) ,处理指定URL,如果cookie失效,追加session的id;如果cookie不失效,不做任何操作。(必须先获取session,否则不追加)
        示例:
            HttpSession session = request.getSession(); //必须先获取session
            String url = "/day06/encodeShowServlet";
            url = response.encodeURL(url);
            response.getWriter().println("<a href='"+url+"'>点我</a> <br/>");



Servlet三种作用域(属性操作)
    servletContext , servlet上下文(管理者),一个web项目,多次会话,共享数据。(一个项目一块内存)
        场景:记录在线人数、浏览次数
    session,服务器会话技术,一次会话,多次请求,共享数据。(一个用户一块内存)
        场景:用户的登录信息
    request,请求,使用请求转发时,一次请求,多个Servlet,共享数据。(一个请求一块内存)
        场景:查询数据,另一个servlet显示
    在完成功能的前提下,尽量使用作用域小的,及时释放内存



验证码
    生成图片工具类CheckNumUtils
        package elec.utils;
        import java.awt.Color;
        import java.awt.Font;
        import java.awt.Graphics;
        import java.awt.image.BufferedImage;
        import java.util.Random;
        import javax.imageio.ImageIO;
        import javax.servlet.http.HttpServletResponse;
        /**
           验证码工具类
           @author Administrator
         *
         */
        public class CheckNumUtils {
            /**
               生成验证码图片并发送到客户端
               @param response 
               @return 验证码
             */
            public static String createCheckImage(HttpServletResponse response) {
                //通知浏览器不缓存
                response.setHeader("Pragma", "No-cache");
                response.setHeader("Cache-Control", "no-cache");
                response.setDateHeader("Expires", 0);
                //生成随机验证码
                Random random = new Random();
                String sRand = "";
                for (int i = 0; i < 4; i++) {
                    String rand = String.valueOf(random.nextInt(10));
                    sRand += rand;
                }
                // 在内存中创建图象
                int width = 55;
                int height = 20;
                BufferedImage image = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_RGB);
                // 获取图形上下文
                Graphics g = image.getGraphics();
                // 设定背景色
                g.setColor(getRandColor(200, 250));
                g.fillRect(0, 0, width, height);
                //设定字体
                g.setFont(new Font("serif", Font.CENTER_BASELINE, 16));
                //画边框
                //g.setColor(new Color(1));
                //g.drawRect(0,0,width-1,height-1);
                //画干扰线
                g.setColor(getRandColor(160, 200));
                for (int i = 0; i < 100; i++) {
                    int x = random.nextInt(width);
                    int y = random.nextInt(height);
                    int xl = random.nextInt(12);
                    int yl = random.nextInt(12);
                    g.drawLine(x, y, x + xl, y + yl);
                }
                //画数字
                for (int i = 0; i < 4; i++) {
                    String rand = sRand.substring(i, i + 1);
                    // 将认证码显示到图象中
                    g.setColor(new Color(20 + random.nextInt(110), 20 + random
                            .nextInt(110), 20 + random.nextInt(110)));
                    //调用函数出来的颜色相同,可能是因为种子太接近,所以只能直接生成
                    g.drawString(rand, 13   i + 6, 16);
                }
                // 图象生效
                g.dispose();
                // 输出图象到页面
                try {
                    ImageIO.write(image, "JPEG", response.getOutputStream());
                    response.getOutputStream().close();
                } catch (Exception e) {
                }
                return sRand;
            }
            //给定范围获得随机颜色
            private static Color getRandColor(int fc, int bc) {
                Random random = new Random();
                if (fc > 255)
                    fc = 255;
                if (bc > 255)
                    bc = 255;
                int r = fc + random.nextInt(bc - fc);
                int g = fc + random.nextInt(bc - fc);
                int b = fc + random.nextInt(bc - fc);
                return new Color(r, g, b);
            }
        }
    页面代码
        <img id="checkImg" src="imageServlet">
    获取验证码
        String checkNum = CheckNumUtils.createCheckImage(response);
        request.getSession().setAttribute("CHECK_NUMBER_KEY", checkNum);
    验证验证码
        String checkNumber = request.getParameter("checkNumber");
        String sessionCheckNumber = (String) request.getSession().getAttribute("CHECK_NUMBER_KEY");
        if(checkNumber == null || checkNumber.equals("")){
            //请输入验证码
        }
        if(!checkNumber.equalsIgnoreCase(sessionCheckNumber)){
            //验证码错误
        }
    点击图片更换验证码
        //checkImg为验证码图片
        checkImg.οnclick=function(){
            checkImg.src="imageServlet?time="+new Date();
        };
    注意:一次性验证码可在每次验证验证码后就删除session中的数据,当再次验证时,如果session中为空,则为表单重复提交



JSP概述
    JSP就是一个java类,也是一个servlet
    特点:html代码嵌入java代码
    JSP扩展名:*.jsp



JSP执行流程
    1 编写jsp页面 (a.jsp)
    2 访问时web服务器(tomcat),tomcat完成以下步骤(在tomcat的web.xml中存在配置路径为*.jsp的servlet,实现类:org.apache.jasper.servlet.JspServlet)
        2.1 读取jsp文件
        2.2 通过jsp文件生成一个java文件 (也是servlet)
            位置:%tomcat%\work\Catalina\localhost\day07\org\apache\jsp\a_jsp.java
                java源码:public final class a_jsp extends org.apache.jasper.runtime.HttpJspBase
                    public abstract class HttpJspBase extends HttpServlet   --> 【jsp就是servlet】
                    _jspService 相当于自定义servlet时doGet或doPost方法
        2.3 将java文件编译生成class文件
        2.4 运行class文件,相当于直接访问servlet,将需要输出的内容发送到浏览器。
    3 访问jsp路径与访问html路径一致



JSP的脚本元素
    声明
        声明方法、字段等
        格式:<%!  java类体可以书写的内容 %>
    表达式
        将表达式的结果发送到浏览器,相当于在servlet中编写 out.print(表达式);
        格式:<%= 表达式 %> 
    代码片段
        格式:<% 方法体可以书写的内容 %>
    注意:
        脚本元素不能嵌套使用
        声明标签声明的变量是成员变量,代码片段声明的变量是局部变量
    面试题
        <%=i%>              //2输出成员 5
        <%int i = 10;%>     //3定义局部变量
        <%=i%>              //4输出局部变量 10
        <%! int i = 5;%>    //1 声明成员
        <% i++; %>          //5将局部+1     11
        <%=i%>              //6输出局部变量 11
        <%=++this.i%>       //7输出成员变量+1 6



JSP指令元素
    指令元素:当前的页面的配置,辅助tomcat生成java源码。
    格式:<%@ 指令名称  属性名称="属性值" ...%>
        指令名称:page、include、taglib
    指令书写
        一个指令可以有多个属性
        同一个指令可以书写多次,但一般一个页面,同样的属性只有出现一次。
    1 page指令
        当前jsp页面的配置信息
        格式:<%@ page  属性名称="属性值" ...%>
            属性
                1 编码
                    pageEncoding : 用于配置当前页面的编码
                    contentType : 用于设置jsp生成servlet响应浏览器的编码
                2 jsp缓存机制
                    autoFlush: 缓存是否自动刷新,缓存如果溢出,则自动刷新,默认为true.
                    buffer :缓存大小,默认:8kb.不自动刷新,页面内容超过缓存大小的话会报错
                3 常用(常见)
                    language : 设置当前jsp可以嵌入的语言。默认值:java
                    info : 描述信息,重写了servlet的getServletInfo()方法,返回描述信息
                    session : 确定当前jsp页面,是否可以直接使用 jsp内置对象session
                    import : 给jsp导入需要包
                        分别导入
                        使用一个import导入,多个类之间使用逗号分隔
                    isELIgnored : 当前jsp页面是否忽略EL表达式的执行,默认:false 可以使用
                    extends : 确定jsp的父类,扩展
                4 jsp错误处理机制
                    errorPage : 指定错误页面,当前jsp出现异常时,会跳到指定页面
                    isErrorPage : 确定当前页面是否是错误处理页.true时可以使用jsp内置变量exception
    2 include指令
      静态包含:一个jsp页面,包含另一个jsp页面,两个jsp生成一个java文件,再运行进行输出。
      格式:<%@ include  file="URL"%>
    3 taglib 指令
        作用:在当前jsp页面中引入指定的标签库
        格式:<%@ taglib prefix="" uri="" %>
            uri : 用于确定标签库描述文件名称(有名称相当于有位置)
            prefix :当前标签库所有标签的使用前缀
                prefix="m"  --> <m:标签名称/>



JSP注释
    jsp格式:<%-- 注释内容 --%>
    java注释:
        //          单行注释
        /  ### */ 多行注释(块注释)
        /*  ###*/ 文件注释(JavaDoc标准注释)
    html注释:<!-- html注释内容 -->
    对比
                    jsp源码     java源码    html源码
        jsp注释     有          无          无
        java注释    有          有          无
        html注释    有          有          有



web项目错误处理机制
    统一管理错误(友好页面)
    配置web.xml
        <error-page>
            <error-code>404</error-code>    异常状态码 和异常类型二选一
            <exception-type>                异常类型
            <location>/404.jsp</location>   位置
        </error-page>



JSP九大内置对象
    内置对象可以直接使用
    1 page , 当前对象(this)
    2 config , servlet配置描述对象ServletConfig
    3 application , 就是servlet上下文对象ServletContext
    4 request ,请求对象HttpServletRequest
    5 response , 响应对象HttpServletResponse
    6 session ,会话HttpSession
    7 out ,输出流JspWriter.
    8 exception ,异常Throwable
    9 pageContext , jsp页面上下文PageContext(jsp页面管理者)
    _jspService方法示例
        public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
                throws java.io.IOException, javax.servlet.ServletException {
            final javax.servlet.jsp.PageContext pageContext;
            javax.servlet.http.HttpSession session = null;
            final javax.servlet.ServletContext application;
            final javax.servlet.ServletConfig config;
            javax.servlet.jsp.JspWriter out = null;
            final java.lang.Object page = this;
            javax.servlet.jsp.JspWriter _jspx_out = null;
            javax.servlet.jsp.PageContext _jspx_page_context = null;
            如果配置了是错误页面,则还有
            java.lang.Throwable exception = org.apache.jasper.runtime,JspRuntimeLibrary.getThrowable(request);



JSP四种作用域(属性操作)
    page ,当前页面(一个页面) 默认作用域
    request ,一次请求,默认一个页面。但使用转发可以涉及页面
    session,一次会话,多个请求。
    application,一个web项目(应用) ,多次会话--一个web项目只有一个对象(ServletContext)



JSP-out对象
    类型JspWriter,但底层使用 out = response.getWriter();
    注意:
        <%
            out.print("aaa");
            response.getWriter().print("bbb");
            out.print("ccc");
        %>
        输出结果为
            bbb aaa ccc(bbb不仅在aaa之前,而且在整个页面之前,<html>和文档声明之前)
    原理:
        servlet和jsp有各自的缓存,而且jsp缓存会先刷新到servlet缓存,然后共同发送到浏览器.
        out.print为jsp缓存,而response.getWriter().print为servlet缓存.jsp缓存溢出才会被追加到servlet缓存.
        可以在out.print("aaa");后手动刷新:out.flush();则会输出:aaa bbb ccc



pageContext类
    pageContext 是jsp 上下文对象(jsp页面管理者)
    api
        1 提供其他8内置对象引用:getXxx()
        2 管理jsp作用域
            管理默认作用域
                getAttribute(java.lang.String name) 获得page作用域指定名称的值
                setAttribute(java.lang.String name, java.lang.Object value) 给page作用域设置值
                removeAttribute(java.lang.String name) 移除所有作用域(page/request/session/application)指定名称的内容
            管理指定作用域
                getAttribute(java.lang.String name, int scope) 获得指定作用域值
                removeAttribute(java.lang.String name, int scope)  移除指定作用域
                setAttribute(java.lang.String name, java.lang.Object value, int scope)  给指定作用域设置内容
        3 提供4常量
            PAGE_SCOPE / REQUEST_SCOPE / SESSION_SCOPE / APPLIACTION_SCOPE
        4 依次获得数据
            findAttribute(java.lang.String name) 依次从page、request、session、application作用域获得数据



JavaBean
    POJO(Plain Old Java Objects)简单的Java对象
    JavaBean 普通类,进行数据封装
        必须提供setter方法和getter方法
            setter方法进行数据添加(修改器),必须set开头,之后名称首字母大写 void setId(String id)
            getter方法进行数据获取(访问器),必须get开头,之后名称首字母大写 String getId()
        提供无参构造(将使用反射创建对象)
    属性(property)通过getter或setter方法获得
        例如:getId -> Id --> id  (去掉get或set前缀,首字母小写)



JSP动作标签
    JSP动作标签,通过<jsp:标签名称>使用
    <jsp:include page="xxx">动态包含,生成两个java文件,只是把输出结果放到一块
    <jsp:forward page="main.jsp" />请求转发



相关类
    Servlet相关类
        Servlet                         servlet父接口
            GenericServlet                  servlet便捷父类,提供了一些便捷方法
                HttpServlet                     http协议的servlet实现,提供doGet和doPost方法
        ServletConfig                   配置对象,可获得servlet初始化参数.(GenericServlet和HttpServlet都实现了此接口)
        RequestDispatcher               请求调度器,用于将资源发送到浏览器
        
        ServletContext                  servlet上下文对象。Servlet管理者,可操作属性,管理资源,获得web项目初始化参数
        ServletRequest                  请求对象
            HttpServletRequest              http协议的请求描述对象
                HttpServletRequestWrapper       HttpServletRequest的装饰类,使开发者可以方便重写request的某个方法(而不是全部,通常要重写getParameter方法处理get请求的中文乱码)
        ServletResponse                 响应对象
            HttpServletResponse             http协议的响应描述对象
                HttpServletResponseWrapper      HttpServletResponse的装饰类,使开发者可以方便重写response的某个方法(而不是全部,可以重写getWriter方法修改输出位置,实现页面静态化)
        HttpSession                     会话对象,可在多个请求间进行数据共享
        Cookie                          servlet 发送到 Web 浏览器保存的少量信息,可用来标识用户
    JSP相关类
        Servlet                         servlet父接口
            GenericServlet                  servlet便捷父类,提供了一些便捷方法
                HttpServlet                     http协议的servlet实现,提供doGet和doPost方法
                    HttpJspBase                     tomcat的HttpJspPage实现
            JspPage                         JSP父接口
                HttpJspPage                     http协议的JSP实现
                    HttpJspBase                     tomcat的HttpJspPage实现
        JspContext                      JSP上下文对象
            pageContext                     提供了获得JSP九大内置对象的方法


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值