3. JSP

JSP简介(Java Server Page)

如果使用Servlet来生成HTML页面,这样Java代码中就嵌入HTML代码,Servlet不仅要处理请求和响应,还要负责画HTML页面,导致业务逻辑处理和前端展示都在这里进行,如果页面布局比较复杂,编码会非常繁琐。而实际项目于中,前端的展示是由专门的页面美工人员来完成,如果在Servlet中处理,美工人员会很麻烦。因此JSP应运而生,它的目的是将 表示的逻辑 从Servlet中分离出来

JSP翻译过程

Created with Raphaël 2.2.0 客户端发出一个要求访问特定jsp的请求 jsp接收到请求,第一次时Tomcat服务器会将jsp解析翻译成servlet源文件,然后编译陈class文件(包括了九大内置对象),并加载到服务器缓存中 servlet容器接收到请求,在jre中解析创建出一个request对象(包含了客户端的请求信息等)和response对象(用于对客户端请求的响应) servlet容器调用客户端访问的特定servlet的service()方法, 并将request对象和response对象传过去 service()方法通过request对象获得相关请求信息, 对请求进行处理,使用response对象生成响应的结果,返回给客户端
  • jsp从本质上来说就是一个servlet。
  • 翻译过程只会在客户端第一次调用jsp时执行。

JSP语法

jsp会使用一些标记语言,除了HTML的一些标记语言,还包括,
jsp指令:
<%@ page %>,指定页面的编程语言,目前java是有效值和默认值。
<%@ include %> ,包含其他文件的内容,可以是jsp文件或者html文件。
<%@ taglib %> ,有关于自定义标签库。

java代码(声明,程序片段,表达式):
<%! %>, 一行代码,多用于声明
<% %>,多行代码,
<%= %>,表达式,会将表达式的值显示在jsp页面上

jsp注释:
<!-- -->,客户端可以看到的注释内容
<%-- -->,客户端查看不到注释内容

jsp九大内置对象

概述

在jsp中,可以在<% %>中直接使用request等对象是因为jsp在编译成servlet时产生了 九大内置对象

  • Servlet:
    • page,当前jsp的this对象
    • config,对应的是servlet中的ServletConfig,获取当前jsp在web.xml中的配置参数
  • Input/Output:
    • request,对应的是servlet中的HttpServletRequest
    • response
    • out,对应的servlet中的PrintWriter
  • Context:
    • pageContext,对应的是jsp中的PageContext,可以获取其他内置对象
    • session,对应的是Servlet中的HttpSession
    • application,对应的是servlet中的ServletContext,用来共享所有用户全局的数据
  • Error:
    • exception,对应的是java中的Exception
详解
Scope(作用域范围)

由大到小:application(整个应用范围) > session(跨越多个servlet) > request(当前servlet) > page(当前page)

request

封装客户端的请求数据,包括请求头,请求方式,cookie,用户输入的数据等。
应用场景:

获取请求的客户端信息,包括客户端的IP地址,各种路径等
request.getHeaderNames(); //获取请求头所有键名的枚举类型
request.getHeader(String name); //获取请求头键名对应的键值的字符串类型
request.getHeaders(String name); //同上,键值为枚举类型

request.getMethod(); //获取请求方式,如 GET
request.getProtocol(); //获取请求的协议的名称和版本,如 HTTP/1.1
request.getRemoteAddr(); //获取客户端的 IP 地址
request.getRemoteHost(); //获取客户端的主机名

request.getRequestURL(); //获取请求的完整的URL,如 http://localhost:8080/GreetingWeb/
request.getScheme(); //获取请求URL使用的协议的部分,如 http
request.getServerName(); //获取请求URL的域名的部分,如 localhost
request.getServerPort(); //获取收到此请求的端口号,如 8080
request.getContextPath(); //获取项目的根路径,如 /GreetingWeb
//小结:组合获取basePath:
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
 + request.getContextPath() + "/";

//获取相对于webapp的路径的三种方法:
request.getRequestURI(); //获取请求的URI,即URL端口号的 后面一部分,如 /GreetingWeb/...
request.getServletPath(); //获取调用的servlet名称或 JSP名称,即URL项目根目录的 后面一部分,如 /index.jsp
request.getPathInfo(); //同上,但是根据web.xml的servlet的url配置不同而获取的值有区别。
//小结:所以获取相对于webapp的路径的方法可以如下:
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
if (contextPath != null && contextPath.length() > 0) {
    uri = uri.substring(contextPath.length());
}

//获取实际的目录地址:
request.getSession().getServletContext().getRealPath("/"); //获取项目实际发布运行的根路径
this.getServletContext().getRealPath("/"); //同上,如 E:\apache-tomcat-8.5.34\webapps\GreetingWeb\
this.getServletContext().getRealPath("url"); //虚拟目录映射为实际目录 
this.getServletContext().getRealPath("./"); //网页所在的目录 
this.getServletContext().getRealPath("../"); //网页所在目录的上一层目录 
//应用:如在工程的webapp下新建一个upload的目录:
String imgName = pic1.getOriginalFilename();
String filepath = request.getSession().getServletContext().getRealPath("/") + "upload" + "\\" + imgName;
File file = new File(filepath);
pic1.transferTo(file);

//获取 请求头所有信息 的例子:
<table width="100%" border="1">
  <tr bgcolor="#949494">
    <th>Header Name</th>
    <th>Header Value(s)</th>
  </tr>
  <%
    Enumeration headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
        String paramName = headerNames.nextElement();
        String paramValue = request.getHeader(paramName);
        out.println("<tr><td>" + paramName + "</td>");
        out.println("<td>" + paramValue + "</td></tr>\n");
    }
  %>
</table>
获取请求的参数,一般是用户在页面进行输入的
request.getParameter("name");
forward,转发用户的请求(小结转发和重定向 url 路径 的写法)
request.getRequestDispatcher("/greeting.jsp").forward(request, response);

//关于请求的转发和重定向的 url 写法小结: 全是相对路径
request.getRequestDispatcher("url")的url三种写法,如(相对于项目根目录写)"greeting.jsp""./greeting.jsp" 
 (相对于容器根目录)"/greeting.jsp"(这种情况特殊,因为getRequestDispatcher()内部自动补充了 baseURL)
response.sendRedirect("url")的url三种写法,如(相对于项目根目录写)"greeting.jsp""./greeting.jsp" 
(相对于容器根目录) request.getContextPath() + "/greeting.jsp" (内部没有补充,所以需要正常加项目目录)
在request范围内传递一些自定义的属性
request.setAttribute("key", value); 
Object object=request.getAttribute("key");
获取Cookie信息
//添加cookie:
Cookie cookie = new Cookie("key", value);
cookie.setMaxAge(60*60*24); //设置cookie存活时间
response.addCookie(cookie); //将cookie放在响应中

//获取cookie:
Cookie[] cookies = request.getCookies();
设置请求的编码方式
request.setCharacterEncoding("UTF-8");
response

响应客户端的请求,可以设置响应内容的格式,响应的头部,状态码等,以及设置cookie,控制请求的重定向,获取PrintWriter对象等。
应用场景:

设置响应内容的格式
response.setContentType("application/msword; charset=GB2312");
设置cookie
Cookie cookie = new Cookie("key", value);
cookie.setMaxAge(60*60*24); //设置cookie存活时间
response.addCookie(cookie); //将cookie放在响应中
控制请求的重定向
response.sendRedirect(request.getContextPath() + "url");
获取PrintWriter对象
PrintWriter out = response.getWriter();
out.print("");
session

http是一种无状态的协议,没有办法维护客户端和服务端之间的请求响应数据,所以jsp通过HttpSession接口来维护客户端和服务端会话的数据。
HttpSession 是server端创建的,每个session创建的时候会分配一个session id,它是一个32位的字符串,通过它唯一标识一个session,每个session对应一个用户,维护并共享用户的所有请求响应的数据。
每个session都有超时时间,tomcat默认是30分钟,通过修改tomcat配置文件或者 调用HttpSession接口来更改默认超时时间(指的是没有收到请求的时间)。
客户端第一次请求,会创建一个session,这是服务器默认的行为。
server维护session的方法是 通过cookie 和 重写URL 来传递session id。

获取session
HttpSession session = request.getSession(true); //true 表示当请求没有session的时候会创建一个session
//实际上是通过获取request的header信息中的cookie信息,拿到JSESSIONID,通过session id 再获取对应的session,如果失效了
//就再创建一个
维护seesion (重点就是在客户端和服务端之间 维护 session id 的方法)
  • 会话cookie(由服务器自动完成创建的,对于浏览器是一次性的)

    会话cookie是保存在浏览器的内存里,它的生命周期是浏览器第一次与服务端建立连接后,服务端会创建一个session,并为浏览器创建一个session id,写到浏览器的会话cookie(cookie名称叫 JSESSIONID)里,当发生请求时,session id 的cookie会作为request header(headerName为 cookie,headerValue为 JSESSIONID=xxx)传到server端,server端通过request可以拿到session id,这样多次的请求响应就可以共享session的数据。这里关键的桥梁就是session id。
    当浏览器关闭时,会话cookie结束。但不意味着session id 在服务端对应的session 结束了,只是浏览器没办法再继续使用session了,再打开浏览器,服务器又会创建一个新session,并将新的session id写到浏览器的会话cookie中。

  • 持久化cookie(自己创建,可以自定义时长的保存在浏览器本地)

    持久化cookie是保存在浏览器本地硬盘里,它的生命周期取决于,创建它时自定义的存活时间,持久化的cookie名字是自定义的,需要手动创建。
    session的持久化cookie的名字不能和会话cookie相同,即JSESSIONID。

    //手动创建 持久化cookie 保存 cookie id 
    HttpSession session = request.getSession(true); //获取session
    session.setMaxInactiveInterval(60*60*10); //设置session 的超时时间,10小时
    
    Cookie cookie = new Cookie("sessionId", session.getId()); //将sessionId写入到持久化的cookie中
    cookie.setMaxAge(60*60*24); //设置cookie存活时间,24小时
    response.addCookie(cookie); //将cookie放在响应中
    
    //使用持久化的 cookie来存放 session id时,重新打开浏览器登陆就不能直接使用request.getSession() 来获取 
    //session了(如果将session id 加到重定向的url 后面就可以用request.getSession(),如,URL;jsessionid=xxx)
    
    //间接获取,通过session id  获取 session:
    HttpSession session = request.getSession().getSessionContext().getSession(sessionId); //使用session上下文获取
    //session,但是官方出于安全性考虑,不建议使用这个方法了。
    //但是我们可以通过HttpSessionListener监听器和全局静态map自己实现一个SessionContext,具体如下:
    
    //MySessionContext.java
    public class MySessionContext {
      private static HashMap<String, HttpSession> mymap = new HashMap<String, HttpSession>();
    
      public static synchronized void AddSession(HttpSession session) {
         if (session != null) {
             mymap.put(session.getId(), session);
         }
      }
    
      public static synchronized void DelSession(HttpSession session) {
         if (session != null) {
             mymap.remove(session.getId());
         }
      }
    
      public static synchronized HttpSession getSession(String sessionId) {
         if (sessionId == null) {
             return null;
         }
    
         return mymap.get(sessionId);
      }
    }
    
    //MySessionListener.java
    public class MySessionListener implements HttpSessionListener {
    
     @Override
     public void sessionCreated(HttpSessionEvent httpSessionEvent)  {
         HttpSession session = httpSessionEvent.getSession();
    
         MySessionContext.AddSession(session);
     }
    
     @Override
     public void sessionDestroyed(HttpSessionEvent httpSessionEvent)  {
         HttpSession session = httpSessionEvent.getSession();
    
         MySessionContext.DelSession(session);
     }
    }
    
    //web.xml中配置 Listener,或者使用注解 @WebListener
     <listener>
      <listener-class>priv.technologyshareweb.listener.MySessionListener</listener-class>
     </listener>
    
  • 重写URL(非持久性,在URL后面加上 jsessionid=xxx)

    由于cookie是一种不安全的方式,而且当浏览器禁用了cookie的时候,就没有办法维护sessionId。这个时候可以重写url,会自动将sessionId加到url后面作为参数,再下一次请求的时候会传到server端。
    有一些开源的框架提供重写url 的功能,只需要导入jar包,做一些相应的配置,就不用每个url 都进行重写。
    也可以通过实现一个Filter 进行url 的重写。

    // java 对 url 重写的方法
    response.encodeURL(url);
    response.encodeRedirectURL(url); //在调用HttpServletResponse.sendRedirect前,应该先调用encodeRedirectURL()方法,
    //否则可能会丢失sesssion信息。所给的URL必须是一个 绝对URL。相对URL不能被接收,会抛 出一个IllegalArgumentException。
    //所有提供给sendRedirect方法的URL都应通过 这个方法运行,这样才能确保会话跟踪能够在所有浏览器中正常运行。
    //如:
    String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
    + request.getContextPath() + "/";
    response.sendRedirec(response.encodeRedirectURL(basePath  + url)); //url为相对路径
    
    //两者的区别:
    response.encodeURL(url);  中的url可以为相对路径,在编码前会自行检查补充为完整的url,是本应用级别的
    response.encodeRedirectURL(url); 中的url必须为绝对路径,在使用重定向前,一定要使用这个方法
    
    //方法内部执行的流程:
    首先判断当前的Servlet是否执行了HttpSession对象的invalidate()方法(当前session是否失效,失效后重新建立新的
    session),如果已经执行返回参数URL。
    接下来判断客户端是否禁用了Cookie,没有禁用直接返回参数URL。
    如果禁用,则在参数URL中附加session ID,返回编码后的URL
session相关方法
  • 维护自定义的属性
session.setAttribute(String key, Object obj);
session.getAttribute(String key);
session.removeAtrribute(String key);
  • 设置session 的超时时间,以秒为单位
session.setMaxInactiveInterval(int interval);
  • 销毁session
session.invalidate();
application

application是全局的内置对象,可以维护所有登陆用户的所有数据,生命周期是在应用的产生和结束之间,所以里面不应该维护一些开销比较大的对象,适合轻量级的属性和对象的维护,比如某个页面的 访问次数,点击量等。

//相应的维护方法
application.setAttribute("key", value);
String s = (String)application.getAttribute("key");
out

用来将信息 输入到 页面 里面。

//相关的方法
flush() //手动刷新,将缓冲区的数据显示出来
IsAutoFlush() //自动刷新,默认为ture,当缓冲区满了后自动显示数据
clearBuffer() //显示缓冲区数据,并清除缓冲区
clear() //直接清除缓冲区
getBufferSize() //获取缓存区大小
getRemaining() //获取缓冲区剩余大小
newLine() //打印一个换行
print() //直接打印
println() //打印后换行
config

用来封装当前page在web.xml中的配置参数,比如servlet的名字,一些初始化的参数,还可以获取servlet的上下文。

getServletContext() 
getServletName() 
getInitParameterNames() 
getInitParameter() 
page

page就是当前jsp的servlet对象,等效于 this。

<%=((Servlet)page).getServletInfo();%>
<%=this.getServletInfo();%>
pageContext

它是用来维护当前page的一些信息,同时它可以访问其他内置对象的属性。

//访问其他内置对象的属性
pageContext.getRequest().getAttribute("key");
pageContext.getSession().getAttribute("sanyang");
pageContext.getServletContext().getAttribute("sanyang");

//维护当前page的一些信息,作用域如果不加,则设置和获取属性都默认是page范围中的。
pageContext.setAttribute("attr1", "value1", PageContext.PAGE_SCOPE);
pageContext.setAttribute("attr2", "value2", PageContext.REQUEST_SCOPE);
pageContext.setAttribute("attr3", "value3", PageContext.SESSION_SCOPE);
pageContext.setAttribute("attr4", "value4", PageContext.APPLICATION_SCOPE);

pageContext.getAttribute("attr1", PageContext.PAGE_SCOPE);
pageContext.removeAttribute("attr1", PageContext.PAGE_SCOPE);	
exception(开发中很少使用)

exception 是用来输出jsp运行过程中的异常到指定的界面。

使用步骤
//1.定义一个异常显示的页面
<%@ page errorPage="ShowError.jsp" %>
//2.在指定的异常显示页面中,设置为页面的异常属性为 true,表示专门用来输出异常的
<%@ page isErrorPage="true" %>
//3.使用exception对象抛出
<% exception.printStackTrace(); %>

EL 和 JSTL

在jsp中,使用<%%>写入java代码,当业务逻辑复杂的时候,servlet也会变得很繁琐,这个时候就需要想办法简化这个插入的java代码,此时 ELJSTL 应运而生。

EL(Expression Language,表达语言)

JSP2.0的新特性,用来访问jsp的数据,简化jsp中数据访问的代码,替换传统的<%=%>表达式。
EL基本表达式:${javabean.variable}
如,${empty param.name ? "My Friend" : param.name}

EL 的 11 种 内置对象

JSTL

替换传统的<%%>java代码片段,包含5个不同的标签。

<c:out>,c标签,JSTL核心标签库
<fmt:message>,国际化相关的标签

各种路径写法小结

  • 对于web中的相对路径:
    / 表示应用容器根目录下,如 /TechnologyShareWeb/index.jsp (特殊:转发中的url 自动补充baseURL,可直接写/index.jsp)
    ./ 表示web项目根目录下,如 ./css/login.css
    什么前缀都不加,直接写,也是表示web项目根目录下,如 css/login.css (不特殊:重定向的url 没有自动补充baseURL,所以要么第一种表示,要么后两种表示)
  • 对于取图片等资源的相对路径: 例子后面遇到再补充
    / 表示根目录下
    ./ 表示当前目录下
    . ./ 表示上一级目录下
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值