Servlet/JSP

ServletContext

Context: 上下文,当前事物存在的前后环境场景。

Servlet 上下文:当前Servlet存在的运行环境。代表Web容器。

  1. 任何获取 ServletContext 的方法获取的对象都是同一个ServletContext对象的引用

    1. 调用从 HttpServlet继承的方法获取ServletContext

      ServletContext ctx1 = getServletContext();
      
    2. 调用request对象getServletContext()方法获取ServletContext

      ServletContext ctx2 = request.getServletContext();
      
  2. 可以使用ServletContext提供的方法与当前Web容器进行通讯

    1. ctx1.getServerInfo() 获取当前容器版本信息
    2. ctx1.getRealPath() 获取当前程序的实际路径,硬盘物理位置
      • 使用这个方法可以获取图片等资源的磁盘位置,进而使用IO API进行操作。
    3. ctx1.getContextPath() 获取当前应用程序的上下文路径
      • 用于拼接web绝对路径,解决路径问题。
  3. ServletContext对象可以绑定共享当前应用的全局数据。

案例:显示Web容器相关信息:

/**
 * 测试ServletContext
 */
public class DemoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 调用从 HttpServlet继承的方法获取
        //   ServletContext 
        ServletContext ctx1 = getServletContext();
        //2. 调用request对象getServletContext()方法
        //   获取ServletContext
        ServletContext ctx2 = request.getServletContext();
        //3. ...
        //“任何”方法获取的ServletContext都是同一个对象

        //ServletContext 代表当前Servlet的运行容器
        //显示当前Web容器的信息
        System.out.println(ctx1.getServerInfo());
        //重要:显示当前Web容器的实际路径(磁盘位置)
        System.out.println(ctx1.getRealPath("/")); 
        //重要:显示当前Web程序的上下文路径(应用程序名)
        System.out.println(ctx1.getContextPath()); 

        response.setContentType(
                "text/html;charset=UTF-8");
        response.getWriter().print("OK"); 
    }

}

  <servlet-mapping>
    <servlet-name>DemoServlet</servlet-name>
    <url-pattern>/demo</url-pattern>
  </servlet-mapping>
  <servlet>
    <description></description>
    <display-name>SetValueServlet</display-name>
    <servlet-name>SetValueServlet</servlet-name>
    <servlet-class>web.SetValueServlet</servlet-class>
  </servlet>

案例:利用ServletContext共享数据

代码:

/**
 * 利用ServletContext共享数据
 */
public class SetValueServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext ctx=getServletContext();
        synchronized (ctx) {
            ctx.setAttribute("test", "Hello World!");
        }
        response.setContentType(
                "text/html; charset=UTF-8");
        response.getWriter().print(
                "添加数据到ServletContext");
    }

}

/**
 * 读取 ServletContext中的数据
 */
public class GetValueServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        ServletContext ctx = getServletContext();
        String msg = null;
        synchronized (ctx) {
            msg = (String)ctx.getAttribute("test");
        }
        response.setContentType(
                "text/html; charset=UTF-8");
        response.getWriter().println("数据:"+msg); 
    }

}

  <servlet>
    <description></description>
    <display-name>SetValueServlet</display-name>
    <servlet-name>SetValueServlet</servlet-name>
    <servlet-class>web.SetValueServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>SetValueServlet</servlet-name>
    <url-pattern>/set</url-pattern>
  </servlet-mapping>
  <servlet>
    <description></description>
    <display-name>GetValueServlet</display-name>
    <servlet-name>GetValueServlet</servlet-name>
    <servlet-class>web.GetValueServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>GetValueServlet</servlet-name>
    <url-pattern>/get</url-pattern>
  </servlet-mapping>

数据共享范围 request session servletContext

Web编程时候,可以利用request session servletContext共享数据,称为共享范围(scope),在使用数据共享范围时候,尽量使用小范围。

关于路径问题

JSP

JSP: Java Server Page: Java 服务器端页面

  1. 为何有JSP
    1. HTML是静态网页,内容固定。适合内部不变的信息
    2. Servlet可以出来动态内容,拼接HTML标签,书写繁琐。
    3. Sun设计了JSP,采用类似于HTML的语法书写Servlet
  2. JSP工作原理:
    1. 将JSP文件先翻译为 .java 的Servlet源文件。
    2. 将 .java 的Servlet源文件编译为 .class
    3. 运行时候执行 .class 文件。
  3. JSP优点:
    1. 可以利用传统HTML编辑器编写JSP
    2. Java自动完成翻译工作。减少了编程量。
  4. JSP适合作为显示界面--“视图”,与Servlet搭配使用
    1. Servlet负责数据计算,业务处理
    2. JSP负责将计算结果和业务处理结果拼接为HTML,显示给用户。

JSP语法

JSP 中可以嵌入Java代码

  1. JSP脚本片段
  2. JSP表达式
  3. JSP声明元素

如上代码方式以及不建议使用了!建议使用JSTL、EL进行替代

JSTL/EL

概念: JSTL 标准标签库 和 EL 表达式语言

JSP中的Java代码丑陋,编写风格与HTML不同,容易出现异常,不方便处理异常。

JSTL出现的历史:

  1. SUN提供了自定义标签技术。与HTML语法类似。
  2. Apache 在自定义标签技术之上,提供了统一通用标签。
  3. Servlet2.5 标准以后将JSTL采纳为默认标准

JSTL就是为了替换 JSP 中的Java代码的!

EL 表达式语法

基本语法:

${表达式}

EL语法:

  1. 从JSP的4个Scope中查询数据,从小到大依次查询
  2. 访问查询到数据的内容
  3. 将数据输出到页面

案例1:

代码:

/**
 * 测试 EL 表达式
 */
public class ElTestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute("num", 10);
        request.setAttribute("arr", new int[]{3,4,5});
        List<Integer> list=new ArrayList<Integer>();
        list.add(55);
        list.add(66);
        list.add(77);
        request.setAttribute("list", list);
        Map<String, String> map=
                new HashMap<String, String>();
        map.put("name","Tom");
        map.put("age", "10");
        request.setAttribute("map", map);
        //转发到JSP页面,利用EL表达式显示数据
        request.getRequestDispatcher("view.jsp")
        .forward(request, response);
    }
}

<%@ page language="java" 
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"> 
<title>Insert title here</title>
</head>
<body>
    <h1>EL表达式显示数据</h1>
    <p>${num}</p>
    <p>${arr[1]}</p>
    <p>${list[1]}</p>
    <p>${map.name}, ${map['age']}</p>
</body>
</html>

案例2:

/**
 * Servlet implementation class ElTest2Servlet
 */
public class ElTest2Servlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Student student = new Student("Jerry", 5);
        request.setAttribute("stu", student); 
        request.getSession()
        .setAttribute("user", student);
        List<Student> list=new ArrayList<Student>();
        list.add(new Student("熊大",10));
        list.add(new Student("熊二",10));
        request.setAttribute("list", list);
        //转发到view2.jsp,利用EL表达式显示数据
        request.getRequestDispatcher("view2.jsp")
        .forward(request, response); 
    }

}

<%@ page language="java" 
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"> 
<title></title>
</head>
<body>
    <h1>EL表达式显示对象数据</h1>
    <p>数据为空:${num}</p>
    <p>${stu.name}</p>
    <p>${list[1].name}</p>
    <p>读取Session中的数据:${user.name}</p>
</body>
</html>

JSTL 标准标签库

JSTL 是一组自定义标签组成的,需要导入解析标签的类文件。

<dependency>
  <artifactId>jstl</artifactId>
  <groupId>jstl</groupId>
  <version>1.2</version>
</dependency>

在页面中使用 taglib 引入标签库

核心标签:

<%@ taglib prefix="c" 
    uri="http://java.sun.com/jsp/jstl/core"%>

格式化标签:

<%@ taglib prefix="fmt" 
    uri="http://java.sun.com/jsp/jstl/fmt"%>

JSTL 包含4个标签库

  1. 核心标签库 core,最常用,提供了用于替换 JSP中Java代码的标签
  2. 格式标签库 fmt,不常用
  3. XML 标签库 xml,不用了解
  4. SQL 标签库 sql,不用了解

Java 的标签库 JSTL、EL 是在服务器端执行的,用于拼接HTML页面。

案例1:

/**
 * 演示JSTL的功能
 */
public class JstlTestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setAttribute("num", 0);
        Student stu = new Student("小明", 20);
        req.setAttribute("user", stu);
        req.getRequestDispatcher("view3.jsp")
        .forward(req, resp); 
    }
}

<%@ page language="java" 
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" 
    uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL</title>
</head>
<body>
    <h1>JSTL</h1>
    <h2>单路分支</h2>
    <c:if test="${num == 0}">
        <p>num 的值是0</p>
    </c:if> 
    <h2>多路分支、双路分支</h2>
    <c:choose>
        <c:when test="${user.age<12}">
            <p>小明是小孩</p>
        </c:when>
        <c:when test="${user.age<22}">
            <p>小明是小伙子</p>
        </c:when>
        <c:otherwise>
            <p>小明是男人</p>
        </c:otherwise>      
    </c:choose>
</body>
</html>

案例2:

/**
 * for each 标签演示
 * 迭代标签,用于遍历集合
 */
public class ForEachServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Student> list=new ArrayList<Student>();
        list.add(new Student("熊大",10));
        list.add(new Student("熊二",10));
        list.add(new Student("光头强",30));
        list.add(new Student("Tom",20));
        list.add(new Student("Andy",40));
        list.add(new Student("传奇",35));
        list.add(new Student("克晶",18));
        request.setAttribute("users", list); 

        request.setAttribute("price", 3453.7);
        request.setAttribute("today", new Date());

        request.getRequestDispatcher("view4.jsp")
        .forward(request, response); 
    }

}

<%@ page language="java" 
    contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" 
    uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" 
    uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>JSTL</title>
</head>
<body>
    <h1>JSTL 迭代标签</h1>
    <!-- 
    <ul>
        <li>熊大,10岁,是小孩</li>
        <li>熊二,10岁,是小孩</li>
        <li>传奇,35岁,是爷们</li>
    </ul>
    -->
    <ul>
        <c:forEach items="${users}" var="user">  
            <li>${user.name}, ${user.age}, 是
                <c:choose>
                    <c:when test="${user.age<12}">小孩</c:when>
                    <c:when test="${user.age<22}">小伙</c:when>
                    <c:otherwise>爷们</c:otherwise>
                </c:choose>
            </li>
        </c:forEach>
    </ul>

    <h2>格式标签</h2>
    <!-- format:格式化,Number:数字  
     1566023.4 -> RMB1,566,023.40
    -->
    <p>跳楼价:<fmt:formatNumber value="${price}"
            pattern="RMB###,###,###.00"/></p>
    <!-- 格式化日期 -->
    <p>仅限今日:<fmt:formatDate value="${today}"
            pattern="yyyy-MM-dd"/> </p> 
</body>
</html>