美文网首页JavaEE
JavaWeb基础恢复之开门篇

JavaWeb基础恢复之开门篇

作者: 平安喜乐698 | 来源:发表于2018-04-17 23:48 被阅读34次
    目录
        0. 环境配置
        1. 创建WebService项目,创建Servlet
        2. Servlet基础知识点
        3. jsp基础知识点
        4. JavaBean
        5. 架构模式
    
    0. 环境配置

    Eclipse官网下载
    Tomcat下载
    MyEclipse官网下载(Mac版请参见 常用网址文章篇下载)

    配置Tomcat(myEclipse默认自带)
    
      1. 下载tomcat Core下zip,解压到/Library,改名为Tomcat。
         cd /Library/Tomcat/bin。
         sudo sh startup.sh 开启服务(出错则chmod +x *.sh)
         sudo sh startup.sh 关闭服务器
         浏览器输入:http://localhost:8080/ 服务器开启则正常显示(则配置成功)
      2. MyEclipse
        Window | Show View | servers  出现视图后右键添加Servie(选择/Library/Tomcat/)
      3. 其他(添加用户)
          编辑/Tomcat/conf/tomcat-users.xml  
          <user username="admin" password="admin" roles="manager"/>
    
    1. 创建一个WebService项目
    1、项目栏空白处,右键 创建web项目
    2、选中项目,右键 运行项目
    
    项目栏空白处右键 选中项目右键 运行结果
    3、在src下创建包
    4、在包下创建Servlet
        访问时路径http://localhost:8093/ProjectTestOne/TestServlet,因为doGet没有任何代码,所以会显示空白页面。
    新版本:
      @WebServlet("/TestServlet")    注解映射
    以前的版本:
      会在web.xml中自动生成如下代码(映射配置),而不是使用注解
      <servlet>
        <description>This is the description of my J2EE component</description>
        <display-name>This is the display name of my J2EE component</display-name>
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>com.sst.cx.HelloServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/servlet/HelloServlet</url-pattern>
      </servlet-mapping>
    
    在包下创建Servlet
    Servlet-1
    Servlet-2
    Servlet-3 Servlet
    5、做个简单的小改变。修改doGet方法并运行,再次访问该Servlet,代码如下:
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
            response.setContentType("text/html");
            PrintWriter out = response.getWriter();
            out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
            out.println("<HTML>");
            out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");
            out.println("  <BODY>");
            out.print("    This is ");
            out.print(this.getClass());
            out.println(", using the GET method");
            out.println("  </BODY>");
            out.println("</HTML>");
            out.flush();
            out.close();
        }
    
    Servlet界面
    2. Servlet基础知识点
    1. 服务器收到客户端的Servlet请求后的流程
      ①检查是否已创建该Servlet实例对象。如果是,则直接执行第③步,否则,执行第②步。
      ②创建该Servlet实例对象,调用init()方法。 
      ③创建一个HttpServletRequest对象(用于封装HTTP请求消息:存储客户端提交过来的数据)和一个HttpServletResponse对象(用于封装HTTP响应消息:用于向客户端传递数据),然后调用Servlet的service()方法(2个对象作为参数)。
      ④WEB应用程序被停止或重新启动前,Servlet引擎将卸载Servlet(卸载前调用destroy()方法)。 
    
    可以看出:
        1、Servlet实例对象创建后直至web容器退出才会销毁。
        2、init方法只被调用一次。service方法在每一次请求都会调用,并新建请求和响应对象调用GET/POST。
    
    一次完整请求流程
    1. HttpServlet
        在原有Servlet接口上添加了一些HTTP协议处理方法,比原有Servlet接口的功能更为强大,它覆写了service方法,会自动判断用户的请求方式去调用GET/POST。
        因此,在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。
    
        public class HelloServlet extends HttpServlet{ 
          public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {}
          public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {}
        }
    
    1. HttpServletRequest
        用于封装HTTP请求消息:存储客户端提交过来的数据
    
    URL地址
            // 获取URL地址
            String requestUrl = request.getRequestURL().toString();
            // 获取URL地址后边的资源路径(域名以后)
            String requestUri = request.getRequestURI();
            // 获取URL地址中的参数
            String queryString = request.getQueryString();
    当前访问用户相关
            // 获取当前访问用户的IP地址
            String remoteAddr = request.getRemoteAddr();
            // 获取当前访问用户的主机名
            String remoteHost = request.getRemoteHost();
            // 获取当前访问用户的端口
            int remotePort = request.getRemotePort();
            //
            String remoteUser = request.getRemoteUser();
    GET/POST
            // GET/POST
            String method = request.getMethod();
            // 
            String pathInfo = request.getPathInfo();
    WEB服务器
            // 获取WEB服务器的IP地址
            String localAddr = request.getLocalAddr();
            // 获取WEB服务器的主机名
            String localName = request.getLocalName();
    
    请求头各个参数
        // 获取所有的请求头
        Enumeration<String> reqHeadInfos = request.getHeaderNames();
        // 循环遍历
        while (reqHeadInfos.hasMoreElements()) {
                String headName = (String) reqHeadInfos.nextElement();
                String headValue = request.getHeader(headName);
        }
        // 获取指定请求头对应的值
        String value = request.getHeader("Accept-Encoding");
        // 循环遍历
        Enumeration<String> e = request.getHeaders("Accept-Encoding");
        while (e.hasMoreElements()) {
                String string = (String) e.nextElement();
        }
    
    获取参数值(常用)
    
        // 保持编码统一(防止POST提交出现乱码,避免不了GET)
        request.setCharacterEncoding("UTF-8");
    
        // 获取指定参数值
        String username = request.getParameter("username");
        // 解决GET提交出现乱码
        name =new String(username.getBytes("ISO8859-1"), "UTF-8") ;
        // 对url中的中文处理
        // ...&name=<%=URLEncoder.encode("徐达沛", "UTF-8")%>
    
        // 获取指定参数值(多个)
        String[] insts = request.getParameterValues("inst");
    
        // 获取所有的参数名(不常用)
        Enumeration<String> paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String name = paramNames.nextElement();
            String value = request.getParameter(name);
        }
    
        // request对象封装的参数是以Map的形式存储的
            Map<String, String[]> paramMap = request.getParameterMap();
            for(Map.Entry<String, String[]> entry :paramMap.entrySet()){
                String paramName = entry.getKey();
                String paramValue = "";
                String[] paramValueArr = entry.getValue();
                for (int i = 0; paramValueArr!=null && i < paramValueArr.length; i++) {
                    if (i == paramValueArr.length-1) {
                        paramValue+=paramValueArr[I];
                    }else {
                        paramValue+=paramValueArr[i]+",";
                    }
                }
            }
    
    传值
    
        // 添加
        request.setAttribute("data", data);
        // 移除
        request.removeAttribute("data");
    
        // jsp使用
        <%=(String)request.getAttribute("data")%>
        // jsp获取所有参数名
        Enumeration<String> attrNames = request.getAttributeNames();
    
    转发/重定向
        一个web资源收到客户端请求后,通知服务器去调用另外一个web资源进行处理,称之为请求转发/307。
        一个web资源收到客户端请求后,通知浏览器去访问另外一个web资源进行处理,称之为请求重定向/302。
    
    方法一
        RequestDispatcher reqDispatcher =this.getServletContext().getRequestDispatcher("/test.jsp");
        reqDispatcher.forward(request, response);
    
    方法二
        request.getRequestDispatcher("/test.jsp").forward(request, response);
    
    1. HttpServletResponse
        用于向客户端传递数据(封装了向客户端发送的 数据、响应头、响应状态码)。
    
    向客户端(浏览器)发送数据
         两个方法冲突(调用了其中的任何一个方法后,就不能再调用另一方法)
    
    方法一
        OutputStream流(是字节流即二进制数据,可以处理任意类型的数据)
    
            ServletOutputStream stream=response.getOutputStream();
            String data = "中国";
            // 获取OutputStream输出流
            OutputStream outputStream = response.getOutputStream();
            // 设置浏览器编码(需要一致,否则乱码)
            response.setHeader("content-type", "text/html;charset=UTF-8");
            // 将字符转换成字节(需要转码)数组,指定以UTF-8编码进行转换,如果不带参数则会根据操作系统的语言环境(中文操作系统使用GB2312的码表)来选择转换码表。
            byte[] dataByteArr = data.getBytes("UTF-8");
            // 写入数据
            outputStream.write(dataByteArr);
            // 不能直接输入数字
            // outputStream.write((1+"").getBytes());
    方法二
        PrintWriter流(是字符流即文本数据,只能处理字符数据,如果用字符流处理字节数据,会导致数据丢失)
    
            // 必须先设置编码,后创建输出。否则无效
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = response.getWriter();
            // 设置浏览器编码
            response.setHeader("content-type", "text/html;charset=UTF-8");
            out.write(1+"");
            out.println("<HTML>");
            out.flush();
            out.close();
    
    向客户端(浏览器)发送响应头
    
        response.addDateHeader(arg0, arg1);
        response.addHeader(arg0, arg1);
        response.addIntHeader(arg0, arg1);
        if(response.containsHeader(arg0)){}
            
        response.setDateHeader(arg0, arg1);
        response.setHeader(arg0, arg1);
        response.setIntHeader(arg0, arg1);
    
    例:
        response.setDateHeader("expries", -1);
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
    【定时刷新】设置refresh响应头控制浏览器每隔5秒钟刷新一次
        response.setHeader("refresh", "5");
    【请求重定向】
        response.sendRedirect("/JavaWeb_HttpServletResponse_Study_20140615/index.jsp");
    
    向客户端(浏览器)发送响应状态码
    
        response.setStatus(arg0);
    
    响应状态码常量
        状态码404:
        状态码200:
        状态码500:
        状态码302:HttpServletResponse.SC_FOUND
    

    HttpServletResponse 使用实例

    例1:下载文件(从网站上)
    
            // 1.获取要下载的文件的绝对路径
            String realPath = this.getServletContext().getRealPath("/download/1.JPG");
            // 2.获取要下载的文件名
            String fileName = realPath.substring(realPath.lastIndexOf("\\")+1);
            // 3.设置content-disposition响应头控制浏览器以下载的形式打开文件
            response.setHeader("content-disposition", "attachment;filename="+fileName);
            // 3.文件名含中文需要+
            response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8"));
            // 4.获取要下载的文件输入流
            InputStream in = new FileInputStream(realPath);
            int len = 0;
            // 5.创建数据缓冲区
            byte[] buffer = new byte[1024];
            // 6.通过response对象获取OutputStream流
            OutputStream out = response.getOutputStream();
            // 7.将FileInputStream流写入到buffer缓冲区
            while ((len = in.read(buffer)) > 0) {
                // 8.使用OutputStream将缓冲区的数据输出到客户端浏览器
                out.write(buffer,0,len);
            }
            in.close();
    
    例2:随机数图片
    
        <img alt="验证码看不清,换一张" src="${pageContext.request.contextPath}/servlet/DrawImage" id="validateCodeImg" onclick="changeImg()">
    
            // 设置refresh响应头控制浏览器每隔5秒钟刷新一次
            response.setHeader("refresh", "5");
            // 1.在内存中创建一张图片,并获取
            BufferedImage image = new BufferedImage(80, 20, BufferedImage.TYPE_INT_RGB);
            //Graphics g = image.getGraphics();
            Graphics2D g = (Graphics2D)image.getGraphics();
            // 1.1  设置图片的背景色,并填充
            g.setColor(Color.WHITE);
            g.fillRect(0, 0, 80, 20);
            // 1.2 设置边框色,并描边
            g.setColor(Color.RED);
            g.drawRect(1, 1, WIDTH - 2, HEIGHT - 2);
            // 1.3 向图片上写数据(设置图片上颜色、字体、文本)
            g.setColor(Color.BLUE);
            g.setFont(new Font(null, Font.BOLD, 20));
            g.drawString(makeNum(), 0, 20);
            // 将随机数存在session中
            request.getSession().setAttribute("checkcode", 随机数);
            // 2.设置响应头控制浏览器浏览器以图片的方式打开
            response.setContentType("image/jpeg");//等同于response.setHeader("Content-Type", "image/jpeg");
            // 3.设置响应头控制浏览器不缓存图片数据
            response.setDateHeader("expries", -1);
            response.setHeader("Cache-Control", "no-cache");
            response.setHeader("Pragma", "no-cache");
            // 4.将图片写给浏览器
            ImageIO.write(image, "jpg", response.getOutputStream());
    
    
        /**
         * 生成随机数字
         * @return
         */
        private String makeNum(){
            Random random = new Random();
            String num = random.nextInt(9999999)+"";
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 7-num.length(); i++) {
                sb.append("0");
            }
            num = sb.toString()+num;
            return num;
        }
    
    
    其他方法
    
           //String random = drawRandomNum((Graphics2D) g,"ch");//生成中文验证码图片
            //String random = drawRandomNum((Graphics2D) g,"nl");//生成数字和字母组合的验证码图片
            //String random = drawRandomNum((Graphics2D) g,"n");//生成纯数字的验证码图片
            //String random = drawRandomNum((Graphics2D) g,"l");//生成纯字母的验证码图片
      /**
         * 在图片上画随机线条
         * @param g
         */
        private void drawRandomLine(Graphics g) {
            // 设置颜色
            g.setColor(Color.GREEN);
            // 设置线条个数并画线
            for (int i = 0; i < 5; i++) {
                int x1 = new Random().nextInt(WIDTH);
                int y1 = new Random().nextInt(HEIGHT);
                int x2 = new Random().nextInt(WIDTH);
                int y2 = new Random().nextInt(HEIGHT);
                g.drawLine(x1, y1, x2, y2);
            }
        }
    
       /**
         * 画随机字符
         * @param g
         * @param createTypeFlag
         * @return
         * String... createTypeFlag是可变参数,
         * Java1.5增加了新特性:可变参数:适用于参数个数不确定,类型确定的情况,java把可变参数当做数组处理。注意:可变参数必须位于最后一项
         */
        private String drawRandomNum(Graphics2D g,String... createTypeFlag) {
            // 设置颜色
            g.setColor(Color.RED);
            // 设置字体
            g.setFont(new Font("宋体", Font.BOLD, 20));
            //常用的中国汉字
            String baseChineseChar = "\u7684\u4e00\u4e86\u662f\u6211\u4e0d\u5728\u4eba\u4eec\u6709\u6765\u4ed6\u8fd9\u4e0a\u7740\u4e2a\u5730\u5230\u5927\u91cc\u8bf4\u5c31\u53bb\u5b50\u5f97\u4e5f\u548c\u90a3\u8981\u4e0b\u770b\u5929\u65f6\u8fc7\u51fa\u5c0f\u4e48\u8d77\u4f60\u90fd\u628a\u597d\u8fd8\u591a\u6ca1\u4e3a\u53c8\u53ef\u5bb6\u5b66\u53ea\u4ee5\u4e3b\u4f1a\u6837\u5e74\u60f3\u751f\u540c\u8001\u4e2d\u5341\u4ece\u81ea\u9762\u524d\u5934\u9053\u5b83\u540e\u7136\u8d70\u5f88\u50cf\u89c1\u4e24\u7528\u5979\u56fd\u52a8\u8fdb\u6210\u56de\u4ec0\u8fb9\u4f5c\u5bf9\u5f00\u800c\u5df1\u4e9b\u73b0\u5c71\u6c11\u5019\u7ecf\u53d1\u5de5\u5411\u4e8b\u547d\u7ed9\u957f\u6c34\u51e0\u4e49\u4e09\u58f0\u4e8e\u9ad8\u624b\u77e5\u7406\u773c\u5fd7\u70b9\u5fc3\u6218\u4e8c\u95ee\u4f46\u8eab\u65b9\u5b9e\u5403\u505a\u53eb\u5f53\u4f4f\u542c\u9769\u6253\u5462\u771f\u5168\u624d\u56db\u5df2\u6240\u654c\u4e4b\u6700\u5149\u4ea7\u60c5\u8def\u5206\u603b\u6761\u767d\u8bdd\u4e1c\u5e2d\u6b21\u4eb2\u5982\u88ab\u82b1\u53e3\u653e\u513f\u5e38\u6c14\u4e94\u7b2c\u4f7f\u5199\u519b\u5427\u6587\u8fd0\u518d\u679c\u600e\u5b9a\u8bb8\u5feb\u660e\u884c\u56e0\u522b\u98de\u5916\u6811\u7269\u6d3b\u90e8\u95e8\u65e0\u5f80\u8239\u671b\u65b0\u5e26\u961f\u5148\u529b\u5b8c\u5374\u7ad9\u4ee3\u5458\u673a\u66f4\u4e5d\u60a8\u6bcf\u98ce\u7ea7\u8ddf\u7b11\u554a\u5b69\u4e07\u5c11\u76f4\u610f\u591c\u6bd4\u9636\u8fde\u8f66\u91cd\u4fbf\u6597\u9a6c\u54ea\u5316\u592a\u6307\u53d8\u793e\u4f3c\u58eb\u8005\u5e72\u77f3\u6ee1\u65e5\u51b3\u767e\u539f\u62ff\u7fa4\u7a76\u5404\u516d\u672c\u601d\u89e3\u7acb\u6cb3\u6751\u516b\u96be\u65e9\u8bba\u5417\u6839\u5171\u8ba9\u76f8\u7814\u4eca\u5176\u4e66\u5750\u63a5\u5e94\u5173\u4fe1\u89c9\u6b65\u53cd\u5904\u8bb0\u5c06\u5343\u627e\u4e89\u9886\u6216\u5e08\u7ed3\u5757\u8dd1\u8c01\u8349\u8d8a\u5b57\u52a0\u811a\u7d27\u7231\u7b49\u4e60\u9635\u6015\u6708\u9752\u534a\u706b\u6cd5\u9898\u5efa\u8d76\u4f4d\u5531\u6d77\u4e03\u5973\u4efb\u4ef6\u611f\u51c6\u5f20\u56e2\u5c4b\u79bb\u8272\u8138\u7247\u79d1\u5012\u775b\u5229\u4e16\u521a\u4e14\u7531\u9001\u5207\u661f\u5bfc\u665a\u8868\u591f\u6574\u8ba4\u54cd\u96ea\u6d41\u672a\u573a\u8be5\u5e76\u5e95\u6df1\u523b\u5e73\u4f1f\u5fd9\u63d0\u786e\u8fd1\u4eae\u8f7b\u8bb2\u519c\u53e4\u9ed1\u544a\u754c\u62c9\u540d\u5440\u571f\u6e05\u9633\u7167\u529e\u53f2\u6539\u5386\u8f6c\u753b\u9020\u5634\u6b64\u6cbb\u5317\u5fc5\u670d\u96e8\u7a7f\u5185\u8bc6\u9a8c\u4f20\u4e1a\u83dc\u722c\u7761\u5174\u5f62\u91cf\u54b1\u89c2\u82e6\u4f53\u4f17\u901a\u51b2\u5408\u7834\u53cb\u5ea6\u672f\u996d\u516c\u65c1\u623f\u6781\u5357\u67aa\u8bfb\u6c99\u5c81\u7ebf\u91ce\u575a\u7a7a\u6536\u7b97\u81f3\u653f\u57ce\u52b3\u843d\u94b1\u7279\u56f4\u5f1f\u80dc\u6559\u70ed\u5c55\u5305\u6b4c\u7c7b\u6e10\u5f3a\u6570\u4e61\u547c\u6027\u97f3\u7b54\u54e5\u9645\u65e7\u795e\u5ea7\u7ae0\u5e2e\u5566\u53d7\u7cfb\u4ee4\u8df3\u975e\u4f55\u725b\u53d6\u5165\u5cb8\u6562\u6389\u5ffd\u79cd\u88c5\u9876\u6025\u6797\u505c\u606f\u53e5\u533a\u8863\u822c\u62a5\u53f6\u538b\u6162\u53d4\u80cc\u7ec6";
            //数字和字母的组合
            String baseNumLetter = "0123456789ABCDEFGHJKLMNOPQRSTUVWXYZ";
            //纯数字
            String baseNum = "0123456789";
            //纯字母
            String baseLetter = "ABCDEFGHJKLMNOPQRSTUVWXYZ";
            //createTypeFlag[0]==null表示没有传递参数
            if (createTypeFlag.length > 0 && null != createTypeFlag[0]) {
                if (createTypeFlag[0].equals("ch")) {
                    // 截取汉字
                    return createRandomChar(g, baseChineseChar);
                }else if (createTypeFlag[0].equals("nl")) {
                    // 截取数字和字母的组合
                    return createRandomChar(g, baseNumLetter);
                }else if (createTypeFlag[0].equals("n")) {
                    // 截取数字
                    return createRandomChar(g, baseNum);
                }else if (createTypeFlag[0].equals("l")) {
                    // 截取字母
                    return createRandomChar(g, baseLetter);
                }
            }else {
                // 默认截取数字和字母的组合
                return createRandomChar(g, baseNumLetter);
            }
            
            return "";
        }
    
        /**
         * 创建随机字符
         * @param g
         * @param baseChar
         * @return 随机字符
         */
        private String createRandomChar(Graphics2D g,String baseChar) {
            StringBuffer sb = new StringBuffer();
            int x = 5;
            String ch ="";
            // 控制字数
            for (int i = 0; i < 4; i++) {
                // 设置字体旋转角度
                int degree = new Random().nextInt() % 30;
                ch = baseChar.charAt(new Random().nextInt(baseChar.length())) + "";
                sb.append(ch);
                // 正向角度
                g.rotate(degree * Math.PI / 180, x, 20);
                g.drawString(ch, x, 20);
                // 反向角度
                g.rotate(-degree * Math.PI / 180, x, 20);
                x += 30;
            }
            return sb.toString();
        }
    
    

    其他

        // 用来获取服务器上的某个资源
        this.getServletContext().getRealPath("/download/1.JPG");
        // 跳转到其他页面
        this.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
    
        <%@include file="/jspfragments/head.jsp" %>
        <jsp:include page="/jspfragments/demo.jsp" />
    
    
        // 重定向
        response.sendRedirect(request.getContextPath()+"/index.jsp");
        // 超链接跳转
        <a href="${pageContext.request.contextPath}/index.jsp">跳转到首页</a>
        // Form表单提交
        <form action="${pageContext.request.contextPath}/servlet/CheckServlet" method="post">
              <input type="submit" value="提交">
        </form>
        <%--使用绝对路径的方式引用js、css--%>
        <script type="text/javascript" src="${pageContext.request.contextPath}/js/index.js"></script>
        <link rel="stylesheet" href="${pageContext.request.contextPath}/css/index.css" type="text/css"/>
        <%--${pageContext.request.contextPath}与request.getContextPath()写法是得到的效果是一样的--%>
        <script type="text/javascript" src="<%=request.getContextPath()%>/js/login.js"></script>
    
    1. 相关

    线程安全问题

      当多个客户端并发访问同一个Servlet时,web服务器会为每一个客户端的访问请求创建一个线程,并在这个线程上调用Servlet的service方法,因此service方法内如果访问了同一个资源的话,就有可能引发线程安全问题。
    
    如:doGet方法中访问全局变量,且多个客户端同时访问会导致此安全问题
    解决:
        synchronized (this) {
            // 在java中,每一个对象都有一把锁,这里的this指的就是Servlet对象
        }
    

    缓存

      设置合理的缓存时间值,避免浏览器频繁向服务器发送请求,提升服务器的性能
    
        response.setDateHeader("expires",System.currentTimeMillis() + 24 * 3600 * 1000);
        // 然后调用response.getOutputStream().write(data.getBytes());
    

    <servlet>说明

        <servlet-mapping>为映射路径(可以有多个)
    
        servlet-name:可以改,保持一致即可
    
        *通配符,任意字符。/* 或 *.hello
    
        <servlet>中  +  <load-on-startup>1</load-on-startup> 
        可以在启动时就创建Servlet的实例对象,并调用init方法
    
        / 缺省Servlet。找不到Servlet时都会调这个
        /Tomcat/conf/web.xml中设置如下默认缺省值
        <servlet>
            <servlet-name>default</servlet-name>
            <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
            <init-param>
                <param-name>debug</param-name>
                <param-value>0</param-value>
            </init-param>
            <init-param>
                <param-name>listings</param-name>
                <param-value>false</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
    初始化参数<init-param>
        当servlet配置了初始化参数后,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。
        WEB容器在启动时为每个WEB应用程序都创建一个对应的ServletContext对象(代表当前web应用,所有Servlet共享同一个,可借此通讯)可通过ServletConfig.getServletContext方法获得ServletContext对象。
    
    
    <servlet>
        <servlet-name>hello</servlet-name>
        <servlet-class>com.sst.cs</servlet-class>
        <init-param>
             <param-name>name</param-name>
             <param-value>hello</param-value>
        </init-param>
    </servlet>
    
    private ServletConfig config;
    public void init(ServletConfig config) throws ServletException {
            this.config = config;
    }
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取在web.xml中配置的初始化参数
        //获取指定的初始化参数
        String paramVal = this.config.getInitParameter("name");
        response.getWriter().print(paramVal);
       
        response.getWriter().print("<hr/>");
        // 获取所有的初始化参数
        Enumeration<String> e = config.getInitParameterNames();
        while(e.hasMoreElements()){
                 String name = e.nextElement();
                 String value = config.getInitParameter(name);
                 response.getWriter().print(name + "=" + value + "<br/>");
        }
    }
    

    ServletContext

    1、不同Servlet间通讯
    Servlet1
    // 获得ServletContext对象
    ServletContext context = this.getServletConfig().getServletContext();
    // 设值
    context.setAttribute("data", data); 
    Servlet2
    // 获得ServletContext对象
    ServletContext context = this.getServletConfig().getServletContext();
    // 取值
    String data = (String) context.getAttribute("data");
    
    
    
    2、取WEB应用的初始化参数
    web.xml下
    <!-- 配置WEB应用的初始化参数 -->
    <context-param>
        <param-name>url</param-name>
        <param-value>jdbc:mysql://localhost:3306/test</param-value>
    </context-param>
    
    // 获取
    ServletContext context = this.getServletContext();
    String contextInitParam = context.getInitParameter("url");
    
    
    
    3、请求转发
    //获取ServletContext对象
    ServletContext context = this.getServletContext();
    //获取请求转发对象(RequestDispatcher)
    RequestDispatcher rd = context.getRequestDispatcher("/servlet/ServletContextDemo5");
    //调用forward方法实现请求转发
    rd.forward(request, response);
    
    
    
    4、读取资源文件
    response.setHeader("content-type","text/html;charset=UTF-8");
    InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/gacl/servlet/study/db4.properties");
    Properties prop = new Properties();
    prop.load(in);
    String driver = prop.getProperty("driver");
    

    会话

      用户打开一个浏览器直到关闭前的整个过程称之为一个会话。保存会话数据的两种技术:
          1.Cookie客户端技术
            将每个用户的数据以cookie的形式存储到浏览器。当用户使用浏览器再去访问服务器中的web资源时,可以回显数据。
          2.Session是服务器端技术
            服务器为每个用户的浏览器创建一个其独享的session对象来存储数据,当用户再去访问服务器中的其它web资源时,可以从session中取出数据。
    
    Cookie
        浏览器一般只允许存放300个Cookie
        每个站点最多存放20个Cookie
        每个Cookie的大小限制为4KB
    例:
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // 设置服务器端以UTF-8编码进行输出
            response.setCharacterEncoding("UTF-8");
            // 设置浏览器以UTF-8编码进行接收,解决中文乱码问题
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            // 获取浏览器的cookie数组
            Cookie[] cookies = request.getCookies();
            // 如果用户是第一次访问,那么得到的cookies将是null
            if (cookies!=null) {
                out.write("您上次访问的时间是:");
                for (int i = 0; i < cookies.length; i++) {
                    Cookie cookie = cookies[I];
                    if (cookie.getName().equals("lastAccessTime")) {
                        Long lastAccessTime =Long.parseLong(cookie.getValue());
                        Date date = new Date(lastAccessTime);
                        out.write(date.toLocaleString());
                    }
                }
            }else {
                out.write("这是您第一次访问本站!");
            }
            
            // 用户访问过之后重新设置用户的访问时间,存储到cookie中,然后发送到客户端浏览器
            // 创建一个cookie,cookie的名字是lastAccessTime
            Cookie cookie = new Cookie("lastAccessTime", System.currentTimeMillis()+"");
            // 设置Cookie的有效期为1天(否则关闭浏览器则失效)
            cookie.setMaxAge(24*60*60);
            // 删除此Cookie
            // cookie.setMaxAge(0);
            // 将cookie对象添加到response对象中,这样服务器在输出response对象中的内容时就会把cookie也输出到客户端浏览器
            response.addCookie(cookie);
    
    /*
        // Cookie中含有中文
        // 设
        Cookie cookie = new Cookie("userName", URLEncoder.encode("你好", "UTF-8"));
        // 取
        URLDecoder.decode(cookies[i].getValue(), "UTF-8")
    */
        }
    
    Session
        服务器创建session后,会把session的id号以cookie的形式回写给客户端,浏览器再去访问服务器时都会带着session的id号。
    
    
        session对象默认30分钟没有使用则服务器会自动销毁session,在web.xml文件中可以手工配置session的失效时间。
         <!-- 设置Session的有效时间:以分钟为单位-->
        <session-config>
          <session-timeout>15</session-timeout>
        </session-config>
    
        // 主动失效
        session.invalidate();
    
    
    例:
    public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            response.setCharacterEncoding("UTF=8");
            response.setContentType("text/html;charset=UTF-8");
            // 获取session,如果session不存在则创建
            HttpSession session = request.getSession();
            // 存储
            session.setAttribute("data", "hello");
            // 获取session的Id
            String sessionId = session.getId();
            // 判断session是不是新创建的
            if (session.isNew()) {
                response.getWriter().print("session创建成功,session的id是:"+sessionId);
            }else {
                response.getWriter().print("服务器已经存在该session了,session的id是:"+sessionId);
            }
        }
    
    浏览器禁用Cookie后的session处理
        解决:URL重写
        当检测到浏览器没有禁用cookie时,就自动不进行URL重写
    
    方法一
    // 用于对表单action和超链接的url地址进行重写
    url = response.encodeURL(url);
    
    方法二
    // 用于对sendRedirect方法中的url地址进行重写
    String url = response.encodeRedirectURL(request.getContextPath()+"/servlet/ListCartServlet");
    response.sendRedirect(url);
    

    表单

    表单例子:
    
        <!--form表单的action属性规定当提交表单时,向何处发送表单数据,method属性指明表单的提交方式,分为get和post,默认为get-->
    <form action="${pageContext.request.contextPath}/servlet/RequestDemo03" method="post">
        <!--输入文本框,SIZE表示显示长度,maxlength表示最多输入长度-->
        编&nbsp;&nbsp;号(文本框):
        <input type="text" name="userid" value="NO." size="2" maxlength="2"><br>
        <!--输入文本框,通过value指定其显示的默认值-->
        用户名(文本框):<input type="text" name="username" value="请输入用户名"><br>
        <!--密码框,其中所有输入的内容都以密文的形式显示-->
        密&nbsp;&nbsp;码(密码框):
        <!--&nbsp;表示的是一个空格-->
        <input type="password" name="userpass" value="请输入密码"><br>
        <!--单选按钮,通过checked指定默认选中,名称必须一样,其中value为真正需要的内容-->
        性&nbsp;&nbsp;别(单选框):
        <input type="radio" name="sex" value="男" checked>男 
        <input type="radio" name="sex" value="女">女<br>
        <!--下拉列表框,通过<option>元素指定下拉的选项-->
        部&nbsp;&nbsp;门(下拉框):
        <select name="dept">
            <option value="技术部">技术部</option>
            <option value="销售部" SELECTED>销售部</option>
            <option value="财务部">财务部</option>
        </select><br>
        <!--复选框,可以同时选择多个选项,名称必须一样,其中value为真正需要的内容-->
        兴&nbsp;&nbsp;趣(复选框): 
        <input type="checkbox" name="inst" value="唱歌">唱歌 
        <input type="checkbox" name="inst" value="游泳">游泳 
        <input type="checkbox" name="inst" value="跳舞">跳舞 
        <input type="checkbox" name="inst" value="编程" checked>编程 
        <input type="checkbox" name="inst" value="上网">上网
        <br>
        <!--大文本输入框,宽度为34列,高度为5行-->
        说&nbsp;&nbsp;明(文本域):
        <textarea name="note" cols="34" rows="5">
         </textarea>
        <br>
        <!--隐藏域,在页面上无法看到,专门用来传递参数或者保存参数-->
        <input type="hidden" name="hiddenField" value="hiddenvalue"/>
        <!--提交表单按钮,当点击提交后,所有填写的表单内容都会被传输到服务器端-->
        <input type="submit" value="提交(提交按钮)">
        <!--重置表单按钮,当点击重置后,所有表单恢复原始显示内容-->
        <input type="reset" value="重置(重置按钮)">
    </form>
    <!--表单结束-->
    
    
    处理表单Servlet例子:
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            //客户端是以UTF-8编码提交表单数据的,所以需要设置服务器端以UTF-8的编码进行接收,否则对于中文数据就会产生乱码
            request.setCharacterEncoding("UTF-8");
            /**
             * 编&nbsp;&nbsp;号(文本框):
               <input type="text" name="userid" value="NO." size="2" maxlength="2">
             */
            String userid = request.getParameter("userid");//获取填写的编号,userid是文本框的名字,<input type="text" name="userid">
            /**
             * 用户名(文本框):<input type="text" name="username" value="请输入用户名">
             */
            String username = request.getParameter("username");//获取填写的用户名
            /**
             * 密&nbsp;&nbsp;码(密码框):<input type="password" name="userpass" value="请输入密码">
             */
            String userpass = request.getParameter("userpass");//获取填写的密码
            String sex = request.getParameter("sex");//获取选中的性别
            String dept = request.getParameter("dept");//获取选中的部门
            //获取选中的兴趣,因为可以选中多个值,所以获取到的值是一个字符串数组,因此需要使用getParameterValues方法来获取
            String[] insts = request.getParameterValues("inst");
            String note = request.getParameter("note");//获取填写的说明信息
            String hiddenField = request.getParameter("hiddenField");//获取隐藏域的内容
            
            String instStr="";
            /**
             * 获取数组数据的技巧,可以避免insts数组为null时引发的空指针异常错误!
             */
            for (int i = 0; insts!=null && i < insts.length; i++) {
                if (i == insts.length-1) {
                    instStr+=insts[I];
                }else {
                    instStr+=insts[i]+",";
                }
            }
            
            String htmlStr = "<table>" +
                                "<tr><td>填写的编号:</td><td>{0}</td></tr>" +
                                "<tr><td>填写的用户名:</td><td>{1}</td></tr>" +
                                "<tr><td>填写的密码:</td><td>{2}</td></tr>" +
                                "<tr><td>选中的性别:</td><td>{3}</td></tr>" +
                                "<tr><td>选中的部门:</td><td>{4}</td></tr>" +
                                "<tr><td>选中的兴趣:</td><td>{5}</td></tr>" +
                                "<tr><td>填写的说明:</td><td>{6}</td></tr>" +
                                "<tr><td>隐藏域的内容:</td><td>{7}</td></tr>" +
                            "</table>";
            htmlStr = MessageFormat.format(htmlStr, userid,username,userpass,sex,dept,instStr,note,hiddenField);
            
            response.setCharacterEncoding("UTF-8");//设置服务器端以UTF-8编码输出数据到客户端
            response.setContentType("text/html;charset=UTF-8");//设置客户端浏览器以UTF-8编码解析数据
            response.getWriter().write(htmlStr);//输出htmlStr里面的内容到客户端浏览器显示
        }
    
    避免表单重复提交
    出现问题
        1.网络卡顿
        2.刷新后在弹框中点击提交按钮
        3.提交后再回到当前页面再点提交
    
    解决1(2、3不能解决):
    1. js
        <script type="text/javascript">
            // 表单是否已经提交标识,默认为false
            var isCommitted = false;
            function dosubmit(){
                if(isCommitted==false){
                    // 提交表单后,将表单是否已经提交标识设置为true
                    isCommitted = true;
                    // 返回true让表单正常提交
                    return true;
                }else{
                    return false;
                }
            }
        </script>
    2. js
        <script type="text/javascript">
            function dosubmit(){
                // 获取表单提交按钮
                var btnSubmit = document.getElementById("submit");
                // 将表单提交按钮设置为不可用,这样就可以避免用户再次点击提交按钮
                btnSubmit.disabled= "disabled";
                // 返回true让表单可以正常提交
                return true;
            }
       </script>
    
    完美解决:session
        在服务器端生成一个唯一的随机标识号,专业术语称为Token(令牌),保存在Session中。然后将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端,然后在服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号。
        在下列情况下,服务器程序将拒绝处理用户提交的表单请求:
            存储Session域中的Token(令牌)与表单提交的Token(令牌)不同。
            当前用户的Session中不存在Token(令牌)。
            用户提交的表单数据中没有Token(令牌)。
    
    1.servlet
        // 创建令牌
        String token = TokenProccessor.getInstance().makeToken();
        // session保存token(令牌)
        request.getSession().setAttribute("token", token);  
        // 跳转到form.jsp页面
        request.getRequestDispatcher("/form.jsp").forward(request, response);
    
    2.form.jsp
        <input type="hidden" name="token" value="${token}"/> 
    
    3.servlet
        boolean b = isRepeatSubmit(request);//判断用户是否是重复提交
        if(b==true){
            System.out.println("重复提交");
            return;
        }
        request.getSession().removeAttribute("token");//移除session中的token
          /**
             * 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
             * @param request
             * @return 
             *         true 用户重复提交了表单 
             *         false 用户没有重复提交表单
             */
            private boolean isRepeatSubmit(HttpServletRequest request) {
                String client_token = request.getParameter("token");
                //1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
                if(client_token==null){
                    return true;
                }
                //取出存储在Session中的token
                String server_token = (String) request.getSession().getAttribute("token");
                //2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
                if(server_token==null){
                    return true;
                }
                //3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
                if(!client_token.equals(server_token)){
                    return true;
                }
                
                return false;
            }
    
    4.创建Token类
    public class TokenProccessor {
    
        /*
         *单例设计模式(保证类的对象在内存中只有一个)
         *1、把类的构造函数私有
         *2、自己创建一个类的对象
         *3、对外提供一个公共的方法,返回类的对象
         */
        private TokenProccessor(){}
        
        private static final TokenProccessor instance = new TokenProccessor();
        
        /**
         * 返回类的对象
         * @return
         */
        public static TokenProccessor getInstance(){
            return instance;
        }
        
        /**
         * 生成Token
         * Token:Nv6RRuGEVvmGjB+jimI/gw==
         * @return
         */
        public String makeToken(){  //checkException
            //  7346734837483  834u938493493849384  43434384
            String token = (System.currentTimeMillis() + new Random().nextInt(999999999)) + "";
            //数据指纹   128位长   16个字节  md5
            try {
                MessageDigest md = MessageDigest.getInstance("md5");
                byte md5[] =  md.digest(token.getBytes());
                //base64编码--任意二进制编码明文字符   adfsdfsdfsf
                BASE64Encoder encoder = new BASE64Encoder();
                return encoder.encode(md5);
            } catch (NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }
    }
    
    3. jsp基础知识点
    JSP(Java Server Pages)
        html只能为用户提供静态数据,而jsp可以为用户提供动态数据(允许在页面中嵌套java代码)。
        注意:在比较正规的开发中,jsp页面是不允许出现java代码的。
    
    JSP、Servlet都可以用于开发动态web资源。
        由于2者各自的特点 加上 显示与数据分离原则, servlet只用来负责响应请求处理数据并传给jsp,jsp则只用来负责显示数据。
    
    
    浏览器向服务器发请求访问的资源本质都是Servlet。
        当访问一个index.jsp页面时,服务器会将index.jsp翻译成一个index_jsp.class(内容在_jspService方法中),在Tomcat服务器的work\Catalina\localhost\项目名\org\apache\jsp目录下可以看到index_jsp.class的源代码文件index_jsp.java。
        该类继承自HttpJspBase,HttpJspBase继承自HttpServlet。
        标签则换成out.write("  <head>\r\n");,嵌套的java则原封不动。
    
    
    请求流程
        1.客户端发送请求
        2.WEB容器接收请求并处理,找到需要执行的*.jsp文件,转换变为*.java文件,编译为*.class文件
        3.服务器执行*.class文件(如果.jsp文件有修改则需重新编译,否则再次访问时使用该class文件)
    

    <html>
        <head>
               <title>第一个 JSP 程序</title>
        </head>
        <body>
               <%
                      out.println("Hello World!");
               %>
        </body>
    </html>
    
    1. 基础语法
    运算符
    
    后缀      () [] . (点运算符)  左到右
    一元      ++ - - ! ~  右到左
    可乘性     * / %   左到右
    可加性     + -     左到右
    移位      >> >>> <<       左到右 
    关系      > >= < <=       左到右
    相等/不等   == !=   左到右
    位与      &   左到右
    位异或     ^   左到右
    位或      |   左到右
    逻辑与     &&      左到右
    逻辑或     ||      左到右
    条件判断    ?:      右到左
    赋值       = += -= *= /= %= >>= <<= &= ^= |=      右到左
    逗号      ,   左到右 
    
    
    
    字面量
    
    布尔值(boolean):true 和 false;
    整型(int):与 Java 中的一样;
    浮点型(float):与 Java 中的一样;
    字符串(string):以单引号或双引号开始和结束;
    Null:null
    
    
    
    语句
    
    <% if (day == 1 | day == 7) { %>
          <p>今天是周末</p>
    <% } else { %>
          <p>今天不是周末</p>
    <% } %>
    
    <% 
    switch(day) {
    case 0:
       out.println("星期天");
       break;
    case 1:
       out.println("星期一");
       break;
    case 2:
       out.println("星期二");
       break;
    case 3:
       out.println("星期三");
       break;
    case 4:
       out.println("星期四");
       break;
    case 5:
       out.println("星期五");
       break;
    default:
       out.println("星期六");
    }
    %>
    
    <%for ( fontSize = 1; fontSize <= 3; fontSize++){ %>
       <font color="green" size="<%= fontSize %>">
        hello
       </font><br />
    <%}%>
    
    <%while ( fontSize <= 3){ %>
       <font color="green" size="<%= fontSize %>">
        world
       </font><br />
    <%fontSize++;%>
    <%}%>
    
    在JSP中,所有的JAVA语句都可以使用。
    
    JSP模版元素
        JSP页面中的HTML内容(定义了页面的结构和外观)。
    
    JSP表达式
        用于将数据输出到页面(表达式的值会被转化成String,不能使用分号来结束)
        <%= 变量或表达式 %>
        解析为java类时=》将表达式的值转为字符串,out.print(值)
    
    
        <%= 表达式 %>
        等价以下
        <jsp:expression>
         表达式
        </jsp:expression>
    
    JSP脚本片断
        <% 
            多行java代码 (定义变量、编写语句,不能定义方法)
            每执行语句后面必须用分号结束
            不能是html标签
        %>
        解析为java类时=》直接原封不动
    
    
        多个脚本片断中的代码可以相互访问
          <%
            for (int i=1; i<5; i++) {
          %>
          <H1>hello</H1>
          <%
            }
          %>
    
    
        <% JAVA代码片段 %>
        等价以下
        <jsp:scriptlet>
           代码片段
        </jsp:scriptlet>
    
    例:
    在网页上打印文本
    <%
    out.println("IP address is " + request.getRemoteAddr());
    %>
    
    JSP声明
        <%! 
            java代码
        %>
        用于定义静态代码块、成员变量和方法。不能使用隐式对象(8)
        解析=》JSP页面中编写的所有代码,默认会翻译到servlet的service方法中, 而jsp声明中的java代码被翻译到_jspService方法的外面。
    
    
        <%! declaration; [ declaration; ]+ ... %>
        等价以下
        <jsp:declaration>
         代码片段
        </jsp:declaration>
    
    例:
        <%! int i = 0; %> 
        <%! int a, b, c; %> 
        <%! Circle a = new Circle(2.0); %> 
    
    JSP注释
        查看源文件时HTML注释可以被看到,JAVA注释和JSP注释则看不到
        1、显式注释(HTML)  <!-- 注释内容 -->
        2、隐式注释(JAVA)  //、/*……*/
        3、独有注释(JSP)   <%-- 注释内容 --%>
    
    1. 内置对象
    9个内置对象
        PageContext pageContext;
        HttpSession session;
        ServletContext application;
        ServletConfig config;
        JspWriter out;
        Object page = this;
        HttpServletRequest request;
        HttpServletResponse response;
        Exception exception;
    
    使用
    <%
    pageContext对象(最常用)
        不仅封装了对其它8大隐式对象的引用,还用于设置/获取值
        getException方法返回exception隐式对象
        getPage方法返回page隐式对象
        getRequest方法返回request隐式对象
        getResponse方法返回response隐式对象
        getServletConfig方法返回config隐式对象
        getServletContext方法返回application隐式对象
        getSession方法返回session隐式对象
        getOut方法返回out隐式对象
    
            // pageContext设值(本页内有效)
            pageContext.setAttribute("name", "pageContext对象");
            // 向其他域中设值(PageContext.APPLICATION_SCOPE、PageContext.SESSION_SCOPE、PageContext.REQUEST_SCOPE、PageContext.PAGE_SCOPE )
            pageContext.setAttribute("name","你好",PageContext.SESSION_SCOPE);
            // pageContext取值
            out.print(pageContext.getAttribute("name")+"<br/>")
            // 从其他域中取值
            String name = (String)pageContext.getAttribute("name",PageContext.SESSION_SCOPE);  
            // 删除
            pageContext.removeAttribute("name");
            // 查找(page→request→session→application,都没找到则返回null)
            String name= (String)pageContext.findAttribute("name");
            // 寻找顺序同上,找不到时返回空字符串
            ${name},
            // 跳转(简化request跳转)不常用,一般使用<jsp:forward>跳转
            pageContext.forward("/pageContextDemo05.jsp");
            // 引入(不常用,一般使用jsp:include)
            <% pageContext.include("/jspfragments/head.jsp"); %>
    
    
    request对象
            // 使用request对象
            out.print(request.getContextPath()+"<br/>");
            // 设值
            request.setAttribute("name", "hello");
    
    
    session对象
            // 设值
            session.setAttribute("name", "值");
            // 取值
            out.print(session.getAttribute("name")+"<br/>");
    
    
    application对象
            // 设值
            application.setAttribute("name", "application对象");
            // 取值
            out.print(application.getAttribute("name")+"<br/>");
    
    
    
    
    out对象
        用于向浏览器显示文本数据
        out对象的类型为JspWriter(缓存功能),设置page指令的buffer属性可以调整它的缓存大小,甚至关闭它的缓存。 
        只有向out对象中写入了内容,且满足如下任何一个条件时,out对象才去调用ServletResponse.getWriter方法,并通过该方法返回的PrintWriter对象将out对象的缓冲区中的内容真正写入到Servlet引擎提供的缓冲区中:
            1.设置page指令的buffer属性关闭了out对象的缓存功能
            2.out对象的缓冲区已满
            3.整个JSP页面结束
    
            // 使用out对象
            out.print("Hello Jsp"+"<br/>");
    
        
    page对象(几乎不用)
        表示当前jsp页面
            // 使用page对象
            out.print("服务器调用index.jsp页面时翻译成的类的名字是:"+page.getClass()+"<br/>");
            // 使用config对象
            out.print("处理请求的Servlet的名字是:"+config.getServletName()+"<br/>");
            // 使用response对象
            out.print(response.getContentType()+"<br/>");
    %>
    

    作用域

    4种范围
        1.当前页(pageContext)
            只作用于当前页面(其他页面无法获取)
        2.一次服务器请求(request)
            一个页面经服务器跳转后的页面也可以获取。
        3.一次会话(session)
            打开浏览器直到关闭
        4.上下文中(application)
            在整个服务器上设置的属性,所有人都可以访问
    
    
    // 设值
    .setAttribute("name", "对象");
    // 取值
    .getAttribute("name");
    // 删除
    .removeAttribute("name");
    
    1. 指令
    并不产生任何输出,只是告诉引擎如何处理JSP页面中的其余部分
    
    格式
        <%@ 指令 属性名="值" %>
    3种:
        page指令       (jsp页面相关属性,如:编码)
        Include指令    (包含其他文件)
        taglib指令     (引入标签库的定义,可以是自定义标签)
    

    page指令

        用于定义JSP页面的各种属性,作用整个JSP页面(无论位置,但建议页面最上的位置)
    
    <%@ page 
        [ language="java" ] 定义JSP页面所用的脚本语言,默认是Java
        [ extends="package.class" ] 指定servlet从哪一个类继承
        [ import="{package.class | package.*}, ..." ] 导入要使用的Java类
        [ session="true | false" ] 指定JSP页面是否使用session
        [ buffer="none | 8kb | sizekb" ] 指定out对象使用缓冲区的大小
        [ autoFlush="true | false" ] 控制out对象的 缓存区
        [ isThreadSafe="true | false" ] 指定对JSP页面的访问是否为线程安全
        [ info="text" ]     定义JSP页面的描述信息
        [ errorPage="relative_url" ] 指定当JSP页面发生异常时需要转向的错误处理页面
        [ isErrorPage="true | false" ] 指定当前页面是否可以作为另一个JSP页面的错误处理页面
        [ contentType="mimeType [ ;charset=characterSet ]" | "text/html ; charset=ISO-8859-1" ] 指定当前JSP页面的MIME类型和字符编码
        [ pageEncoding="characterSet | ISO-8859-1" ] 编码
        [ isELIgnored="true | false" ] 指定是否执行EL表达式
    %>
    
    
    例:
        <%@ page contentType="text/html;charset=gb2312"%>
        <%@ page import="java.util.Date"%>
        <%@ page contentType="text/html;charset=gb2312" import="java.util.Date"%>
    
    page指令的import属性
        在Jsp页面中,Jsp引擎会自动导入下面的包
            java.lang.*
            javax.servlet.*
            javax.servlet.jsp.*
            javax.servlet.http.*
    
        <%@ page import="java.util.*,java.io.*,java.sql.*"%>
    
    page指令的pageEncoding、errorPage、isErrorPage属性
        errorPage:值必须使用相对路径。如果以“/”开头,表示相对于当前Web应用程序的根目录(注意不是站点根目录)。
        isErrorPage:显式声明页面为错误页面。exception.getMessage()获取错误信息
         <%@ page language="java" contentType="text/html; charset=UTF-8" import="java.util.*" errorPage="/ErrorPage/error.jsp" pageEncoding="UTF-8"%> 
        <%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isErrorPage="true"%>
    
    
    web.xml指定整个网站出错时的错误页
    <error-page>
        <error-code>404</error-code>指定错误的状态码
        <exception-type>java.lang.ArithmeticException</exception-type>
    <exception-type>指定异常类的完全限定名(可不写)
        <location>/ErrorPage/404Error.jsp</location>指定状态码下的错误处理页面
    </error-page>
    
    JSP页面的errorPage属性优先级更高
    
    
    注意:
        如果错误页面大小比较小,在IE浏览器下是无法跳转到错误页面的。(尽量页面大小大于1024bytes)
    

    include指令

    2种形式:
        @include指令
        <jsp:include>指令
    
    @include指令
        <%@include file="/jspfragments/head.jspf" %>
        静态引入,直接内容替换导入。(注意不能声名两个同名变量)
        解析=》将两个jsp转成一个Servlet
    
    被引用的文件:
        可以使用任意的扩展名(建议为.jspf),都会按照jsp页面处理
    
    jsp:include指令
        动态包含,对jsp文件先处理再导入(其他文件则直接替换内容)。
        对.jspf文件中的内容作为纯文本处理,不执行jsp指令。解决:
        方法1.修改web.xml;方式2.修改tomcat服务器的web.xml
        <!-- 让jspf扩展名同样成为JSP Servlet处理的文件。 -->
        <servlet-mapping>
            <servlet-name>jsp</servlet-name>
            <url-pattern>*.jspf</url-pattern>
            <url-pattern>*.jsp</url-pattern>
        </servlet-mapping>
    
    引入标签库的定义,可以是自定义标签
    
    <%@ taglib uri="uri" prefix="prefixOfTag" %>
    等价以下
    <jsp:directive.taglib uri="uri" prefix="prefixOfTag" />
    
    1. JSP标签
        用于在Jsp页面中提供业务逻辑功能,避免在JSP页面中直接编写java代码,造成jsp页面难以维护
    
    <jsp:动作名 属性名="属性值" />
    动作名
      include       用于包含静态/动态文件。
      useBean       寻找和初始化一个JavaBean组件
      setProperty   设置 JavaBean组件的值
      getProperty   将 JavaBean组件的值插入到 output中
      forward       从一个JSP文件向另一个文件传递一个包含用户请求的request对象
      plugin        用于在生成的HTML页面中包含Applet和JavaBean对象
      element       动态创建一个XML元素
      attribute     定义动态创建的XML元素的属性
      body          定义动态创建的XML元素的主体
      text          用于封装模板数据
      param
    属性
      id属性  唯一标识
      scope属性    page, request, session, 和  application
    
    <jsp:include>标签  
        <jsp:include page="relativeURL | <%=expression%>" flush="true|false" />
        动态引入
        解析=》会被转成2个Servlet
    
    
    include指令:是在JSP文件被转换成Servlet时引入文件,
    jsp:include:在页面被请求时引入文件
    flush:定义在包含资源前是否刷新缓存区
    
    例:
    <jsp:include page="/jspfragments/head.jsp"/>
    
    <jsp:forward>标签  (跳到另一页)
        <jsp:forward page="relativeURL | <%=expression%>" /> 
    
    例:
    <jsp:forward page="/forwarddemo02.jsp"/>
    
    <jsp:param>标签
         <jsp:forward>标签  和  <jsp:include>标签  的子标签
         <jsp:param name="parameterName" value="parameterValue|<%= expression %>" />
    
    例:
    <jsp:include page="/jspfragments/Inc.jsp">
        <jsp:param name="parm1" value="hello" />
        <jsp:param name="parm2" value="gacl" />
    </jsp:include>
    
    <jsp:plugin>标签
    
    例:
    <jsp:plugin type="applet" codebase="dirname" code="MyApplet.class"
                               width="60" height="80">
       <jsp:param name="fontcolor" value="red" />
       <jsp:param name="background" value="black" />
       <jsp:fallback>
          Unable to initialize Java Plugin
       </jsp:fallback>
    </jsp:plugin>
    
    <jsp:useBean>标签
    
    例:
    <jsp:useBean id="test" class="com.runoob.main.TestBean" />
    <jsp:setProperty name="test" 
                        property="message" 
                        value="输出..." />
    <jsp:getProperty name="test" property="message" />
    
    4. JavaBean
    JavaBean(一个遵循特定写法的Java类):
        1.必须具有一个无参的构造函数
        2.属性必须私有化,且通过public类型的方法(遵守一定的命名规范)对外。
    
    
        JavaBean可以有多个属性,属性可以是任意类型。
        每个属性通常都需要具有相应的setter(属性修改器,必须以小写的set前缀开始,后跟属性名-第一个字母大写)、 getter方法(属性访问器,必须以小写的get前缀开始,后跟属性名-第一个字母大写)。只有set方法的属性:只写属性。只有get方法的属性:只读属性。
    
    例:
    
    /**
     * Person类
     */
    public class Person {
    
        //------------------Person类封装的私有属性---------------------------------------
        // 姓名 String类型
        private String name;
        // 年龄 int类型
        private int age;
        //是否已婚 boolean类型
        private boolean married;
       
        
        //------------------Person类的无参数构造方法---------------------------------------
        /**
         * 无参数构造方法
         */
        public Person() {
        }
       
        
        //------------------Person类对外提供的用于访问私有属性的public方法---------------------------------------
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
    
        public boolean isMarried() {
            return married;
        }
        public void setMarried(boolean married) {
            this.married = married;
        }
    }
    

    使用

    在JSP页面中:
    
    <jsp:useBean>标签
        用于查找JavaBean组件,不存在则创建。
    <jsp:setProperty>标签
        用于设置一个JavaBean组件的属性。
    <jsp:getProperty>标签
        用于获取一个JavaBean组件的属性。
    
    <jsp:useBean>标签
        查找JavaBean组件,不存在则创建
        <jsp:useBean id="beanName" class="package.class" scope="page|request|session|application"/>
      "id" :实例对象名
      "class":必须带有包名的完整类名
      "scope":作用域范围,默认值是page。
    
    例:
        <jsp:useBean id="person" class="com.cx.Person" scope="page"/>
        <% person.setName("hello"); %>
        <%=person.getName()%>
    
    <jsp:setProperty>标签
        <jsp:setProperty name="beanName" property="propertyName" value="string字符串"/>
        <jsp:setProperty name="beanName" property="propertyName" value="<%= expression %>" />
        <jsp:setProperty name="beanName" property="propertyName" param="parameterName"/>
        <jsp:setProperty name="beanName" property= "*" />
    
    
    例:
    <jsp:useBean id="person" class="com.cx.Person" scope="page"/>
    可以将字符串转为8种基础数据类型,不能转换复合数据类型(如:Date)
    <jsp:setProperty property="name" name="person" value="hello"/>
    将指定param_name参数的值,为属性赋值
    <jsp:setProperty property="name" name="person" param="param_name"/>
    将所有参数的值,为属性赋值
    <jsp:setProperty property="*" name="person"/>
    <%=person.getName()%>
    
    <jsp:getProperty>标签
        <jsp:getProperty name="beanInstanceName" property="PropertyName" />
    
    例:
    <jsp:getProperty property="name" name="person"/>
    
    5. 架构模式

    JavaBean+JSP架构模式

    适合小型业务
        JavaBean负责封装数据(用于保存和获取)。
        JSP负责处理请求和显示数据。
    

    JavaBean+JSP+Servlet架构模式

    MVC模式
        Model(模型层)
            JavaBean负责封装数据(用于保存和获取和处理数据)。
        View(视图层)
            JSP负责显示数据。
        Controller(控制器层)
            Servlet负责让JavaBean处理数据,并将结果传给jsp。
    
    缺点:
        1.控制层复杂
        2.从获取请求参数到给模型赋值比较繁琐,可交由框架处理
        3.跳转至其他页面和传递模型 严重依赖Servlet API
        4.javaBean复杂,可以为模型层、业务逻辑层、持久层
    

    相关文章

      网友评论

        本文标题:JavaWeb基础恢复之开门篇

        本文链接:https://www.haomeiwen.com/subject/fahmkftx.html