1、JSP:入门学习
JSP概念
* Java Server Pages: java服务器端页面
* 可以理解为:一个特殊的页面,其中既可以指定定义html标签,又可以定义java代码
* 用于简化书写!!!(为什么可以简化书写?视频12-3.30解析)
对于一些页面,里面既有静态的html标签显示的数据,又有需要通过java代码动态生成的数据。我们需要使用java代码,使用Response对象往页面响应动态数据以及静态HTML标签,这样通过java响应各种HTML静态标签相当麻烦。
而JSP可以让我们在一个页面里面使用HTML写静态内容以及java代码写动态内容,这样就很方便。
相应的代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%--JSP页面既可以写Java代码,也可以写html标签--%>
<%
//JSP写java代码
System.out.println("hello JSP");//访问index.jsp,这一句会打印到控制台
%>
<%--JSP写HTML标签
访问index.jsp,这一句会显示到浏览器页面
--%>
<h1>hi JSP</h1>
</body>
</html>
原理:JSP本质上就是一个Servlet。(见视频13解析)
我们将访问JSP页面的服务器启动,控制台第一行的Using CATALINA_BASE: 的属性,就是当前项目的配置目录:C:\Users\Administrator.IntelliJIdea2017.3\system\tomcat_java-demo1。里面有2个文件夹,一个是conf一个是logs。我们访问index.jsp,里面多了一个文件夹:work,这个work里面放的就是我们JSP对应的java文件以及class文件。
我们发现JSP生成的类index_jsp继承HttpJspBase,HttpJspBase是Apache内部提供的类,前面的资料提供了JSP的源码,在:D:\资源\黑马就业班\00.讲义+笔记+资料\JavaWeb\19.会员版(2.0)-就业课(2.0)-Servlet和HTTP请求协议\day05_Servlet&HTTP&Request\资料\tomcat-src\apache-tomcat-8.5.31-src\java\org\apache\jasper\runtime 可以找到这个类的源码。发现HttpJspBase继承HttpServlet。因此我们可以说JSP就是一个Servlet。
将来我们可以把HTML标签定义在JSP中,这个index_jsp类会将HTML标签自动输出到页面上,这样我们就不需要自己去输出HTML标签。
JSP的脚本:JSP定义Java代码的方式
1. <% 代码 %>:定义的java代码,在service方法中。service方法中可以定义什么,该脚本中就可以定义什么。
2. <%! 代码 %>:定义的java代码,在jsp转换后的java类的成员位置。可以定义成员变量或者成员方法、代码块,静态代码块等(用的比较少,我们为了避免线程安全问题,一般不定义成员信息)
3. <%= 代码 %>:定义的java代码,会输出到浏览器页面上。输出语句中可以定义什么,该脚本中就可以定义什么。相当于使用Response的getWriter().write()方法将java定义的数据输出到浏览器页面上,这个输出语句定义在service方法里面。
相应代码如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
//在这个脚本中定义index_jsp.java类中service方法内可以定义的内容
System.out.println("hello JSP");
int i = 5;//定义service方法内局部变量
%>
<%--这个脚本定义的是index_jsp.java类成员位置的信息,可以定义成员变量或者成员方法、代码块,静态代码块等--%>
<%!
int i = 3;
%>
<%--这个脚本定可以将其里面的值输出到浏览器页面上--%>
<%--就近原则,输出局部变量i=5,因为i=5是定义在service方法的局部变量,而这个脚本也是定义在service方法里面,因此i=5 会被先访问到--%>
<%=
i
%>
</body>
</html>
JSP的内置对象:在jsp页面中不需要获取和创建,可以直接使用的对象,jsp一共有9个内置对象。
* 今天学习3个:
* request
* response
* out:字符输出流对象。可以将数据输出到页面上。和response.getWriter()类似
* response.getWriter()和out.write()的区别:
* 在tomcat服务器真正给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据。
* response.getWriter()数据输出永远在out.write()之前
原因:视频15-5.40。为了避免混乱,我们只只有out往页面输出就可以。
代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
//out与Request对象是JSP的内置对象,可以直接使用
String contextPath = request.getContextPath();
out.print(contextPath);//contextPath被打印浏览器页面上
%>
<%
//后使用response.getWriter()对象输出数据
response.getWriter().write("hahaha");
%>
<%--发现response.getWriter()始终会在out对象前面输出数据--%>
</body>
</html>
案例:改造Cookie的显示访问时间的案例
首先,可以先修改JSP的模板,视频16-00.50的介绍。代码如下(建议黏贴到JSP页面,比较容易看)。下面这种代码写法较难阅读,且难写,我们一般不会这样写。
<%@ page import="java.net.URLDecoder" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.net.URLEncoder" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%--
将前面显示访问时间的案例转换为JSP的代码,需要注意几点
1)所有通过Response对象的getWriter()方法要输出到浏览器页面的java代码中的变量,如value,它是java代码的变量,
输出要通过<%= %>脚本输出;(当然也可以在<% %>脚本中使用getWriter()直接输出)
2)所有通过Response对象的getWriter()方法要输出到浏览器页面纯文本或者HTML语言,可以直接写在当前JSP页面上,
不需要写在上面脚本中(当然也可以在<% %>脚本中使用getWriter()直接输出这些HTML,就是很麻烦)
3)其他的所有java的代码要写在<% %>脚本中
doPost与doGet方法也是在service方法中,他们里面的代码也可以写在脚本<% %>中,且doPost与doGet方法体不需要写上去,写方法内容即可
--%>
<%--
我们将前面doPost的方法体全部复制到<%%>中,没有报错。说明所有java代码都可以写到<%%>里面
--%>
<%--首先,普通java代码--%>
<%
//由于我们要使用Response返回文字到浏览器上显示,先设置Response的编码方式并告知浏览器数据的数据格式以及编码
//response.setContentType("text/html;charset=utf-8");
//不需要设置response的编码,上面设置了
boolean flag = false;//判断有没有名为“lastTime”的Cookie存在,开始没有Cookie存在
//获取Cookie
Cookie[] cookies = request.getCookies();
//如果Cookie存在
if(cookies != null && cookies.length > 0)
{
//对由于的Cookie进行遍历
for (Cookie cookie : cookies)
{
String name = cookie.getName();//获取Cookie的名字
//可能有多个Cookie,我们想操作哪个封装时间的Cookie,那么先判断Cookie的名字是否为lasttime
if("lastTime".equals(name))
{
//如果找到lasttime的Cookie,首先将flag设置为true,表示之前已经创建了Cookie,已经存在,
// 如果不设置,那么flag=false,访问的时候还是就会进入上面的循环创建Cookie,注意
flag = true;
String encodeTime = cookie.getValue();//获取上一次访问的时间
System.out.println("解码前时间:"+encodeTime);
String decodeTime = URLDecoder.decode(encodeTime, "utf-8");//使用同一个编码方式解码时间
System.out.println("解码后时间:"+decodeTime);
%>
<%--HTML语言直接写在页面上,而通过getWriter()方法写到浏览器页面的java变量写在输出脚本上--%>
<h1>欢迎回来,您上次访问时间为:<%=decodeTime%></h1>
<%--其他普通java代码同样写到普通脚本--%>
<%
/**
* 我们也可以先设置Cookie的新值,再获取Cookie上一次的值。
* 因为只有浏览器访问后响应,Cookie的值才会被更新。因此这里先设置新的Cookie值再将旧的值取出来也是可以的
*/
//再次获取当前时间并编码
Date date = new Date();
SimpleDateFormat sd = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String time = sd.format(date);
System.out.println("编码前:" + time);
String encodeTime_2 = URLEncoder.encode(time, "utf-8");
System.out.println("编码后:"+encodeTime_2);
cookie.setValue(encodeTime_2);//将当前时间设置到Cookie中
//设置cookie的存活时间
cookie.setMaxAge(60 * 60 * 24 * 30);//一个月
response.addCookie(cookie);//再次将Cookie写入Response
break;//获取到时间Cookie后达到目的,我们不再遍历,跳出循环
}
}
}
/**
* 注意,判断Cookie不存在一个放在Cookie存在后面。因为每次进来,虽然前面已经设置了Cookie,但是每次进来我们都将flag设置为false
* 如果先判断Cookie不存在,每次都满足flag == false,每次都会执行首次访问的代码
* 如果先判断Cookie存在,里面会把flag设置为true,这样就不会每次都执行首次访问的代码
*/
//Cookie不存在。
if(cookies == null || cookies.length == 0 || flag == false)//这三种情况代表Cookie不存在,flag == false表示有Cookie但是没有lastTime的Cookie
{
//没有Cookie,第一次访问
//设置Cookie的value
//获取当前时间的字符串,重新设置Cookie的值,重新发送cookie
Date date = new Date();
SimpleDateFormat sd = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String time = sd.format(date);
System.out.println("编码前:" + time);
//直接将时间字符串写入Cookie会报错,我们使用URL编码编码时间
String encodeTime = URLEncoder.encode(time, "utf-8");
System.out.println("编码后:"+encodeTime);
//创建一个Cookie,设置值为当前时间
Cookie ck = new Cookie("lastTime", encodeTime);
ck.setMaxAge(60*60*24*30);//设置Cookie在硬盘中保存30天
//将Cookie添加到Response
response.addCookie(ck);
//使用Response返回浏览器文字,前面设置过编码,这里不需要再次设置
%>
<%--html标签同样直接写到JSP页面上--%>
<h1>您好,欢迎您首次访问</h1>
<%
}
%>
</body>
</html>