JavaEE

JavaWeb基础恢复之开门篇

2018-04-17  本文已影响34人  平安喜乐698
目录
    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复杂,可以为模型层、业务逻辑层、持久层
上一篇下一篇

猜你喜欢

热点阅读