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九大内置对象的方法


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值