文章目录
jsp的基本用法
在jsp中,主要有下面几种语法:
- <%…%>,两个%里面用于书写java代码,此时这个相当于java中的方法,所以在java的方法里面可以些什么,那么在<%…%>里面就可以写什么。
- <%=…%>,用于输出,相当于java中的输出,所以里面可以写变量,那么就会输出这个变量的值,如果是一个方法,那么就会输出这个方法返回值。
- <%!..%>:相当于类,所以可以用于定义全局变量和方法。
例如下面的例子中:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>演示jsp中的几种方式</title>
</head>
<body>
<%
int a = 10;//定义一个局部变量
%>
<%
out.print(a++);//在这里通过out对象,调用print方法来输出a的值,然后a自增
%>
<%!
//定义全局变量和方法
int a = 100;
public void fun1(){
System.out.println(a);
}
%>
<%
out.print(this.a++);//输出全局变量,然后自增
fun1();
%>
</body>
</html>
测试结果:
jsp的原理:
jsp其实是一个特殊的Servlet,那么当我们第一次访问这个jsp的时候,服务器会将其编译成为java文件(这个java文件其实是一个Servlet类),然后再把这个java文件编译成为.class文件.之后创建Servlet类对象。然后调用service方法。当下一次再次访问的时候,就会直接调用service方法了。
这就是为什么上面中<%!..%>中的a每次访问的值都会不一样,这就是因为再第一次访问的时候,我们输出的是它的初始值,然后下一次请求的时候,直接调用service方法来输出它的值。所以每次请求都会不一样。只有在tomcat服务器关闭了,那么这个servlet就结束了,此时当我们再次打开tomcat服务器来请求这个jsp的时候,那么就会再次从a的初始值开始。
而在<%…%>中的a由于是定义在方法中,方法已结束,这个局部变量就结束了,所以每次发送请求,<%%>中的a都是一样的输出。
jsp和Servlet的分工
- jsp主要是负责请求页面时发送数据,以及在响应的时候显示数据
- Servlet则是负责中间处理过程.
例如下面的例子中,add1.jsp和add2.jsp由jsp来负责的,用于请求时发送数据以及响应时的显示页面,而AServlet则是在中间过程处理数据的过程.
<!--add1.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>add1</title>
</head>
<body>
<form action="/AServlet" method="post">
整数1: <input type="text" name="num1"><br>
整数2: <input type="text" name="num2"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
<!--add2.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>add2</title>
</head>
<body>
<%
//利用jsp中已经建立的对象request,调用getAttribute,从而获取名字位sum的参数值
int sum = (Integer)request.getAttribute("sum");//这是利用到了request域对象
out.println(sum);
System.out.println(sum);
%>
</body>
</html>
Servlet类:
public class AServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
int num1 = Integer.parseInt(request.getParameter("num1"));//获取请求参数num1的值
int num2 = Integer.parseInt(request.getParameter("num2"));
int result = num1 + num2;
//将运算结果保留到request域中
request.setAttribute("sum",result);
//请求转发到add2.jsp中
request.getRequestDispatcher("add2.jsp").forward(request,response);
}
}
测试结果:
Cookie和Session
Cookie:由服务器创建,并且随着响应报文发送给客户端,保存到客户端中的一小段数据。当下一次客户端再次访问同一服务器的时候,那么这个cookie就会随着请求报文一起发送给服务器。
服务器可以通过Set-Cookie响应头来创建cookie。但是如果创建多个cookie,那么不可以利用setHeader(“Set-Cookie”,“cookie_name=cookie_value”),因为setHeader创建的响应头是单值的。所以通过调用addHeader(“Set-Cookie”,“cookie_name1=cookie_value”);来创建多个cookie.
创建多个cookie之后,那么在响应报文中,Cookie响应头的值是多个cookie之间用;隔开,然后每个cookie都是以cookie_name=cookie_value的形式出现。例如当我们由"aaa=AAA","bbb=BBB"这2个cookie,那么此时的Cookie响应头的值为:“aaa=AAA;bbb=BBB”.
在javaweb中使用cookie:
- 原始方式:response来调用addHeader(“Set-Cookie”,“cookie_name=cookie_value”)来创建多个cookie对象。然后利用request对象调用getHeader(“Cookie”)来获取请求头Cookie的值,返回的是一个字符串,例如"aaa=AAA;bbb=BBB"的形式,这样我们还需要将这个字符串分割成为数组,才可以获取每个cookie字符串,要想获取cookie的名字,还要再进行响应的操作,相对麻烦。
- 便捷方式
response调用addCookie(cookie1)方法来添加cookie,而在添加之前,我们需要创建cookie对象。
然后来利用request调用getCookies()方法来返回一个cookie数组。这样,我们只要遍历这个cookie数组,每获得一个cookie,就可以调用响应的方法,就可以得到这个cookie的名字以及值。
<!--cookie1下的a.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>添加cookie</title>
</head>
<body>
<h1>添加cookie</h1>
<%
/*通过调用addHeader来添加Set-Cookie响应头,那么这个响应头是多汁的,
这样才可以添加多个cookie。否则,如果调用的是setHeader来添加cookie,
那么这个响应头是单值的。
response.addHeader("Set-Cookie","aaa=AAA");
response.addHeader("Set-Cookie","bbb=BBB");*/
Cookie cookie1 = new Cookie("aaa", "AAA");
//调用addCookie来添加cookie
response.addCookie(cookie1);
Cookie cookie2 = new Cookie("bbb", "BBB");
response.addCookie(cookie2);
%>
</body>
</html>
<!--cookie1下的b.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>获取cookie</title>
</head>
<body>
<h1>获取cookie</h1>
<%
/*
通过获取请求头Cookie,从而获取cookie中的值
String cookie = request.getHeader("Cookie");
String[] split = cookie.split(";");
for(String s: split) {
out.println(s + "<br>");
}
但是通过获取cookie响应头的值返回的是一个字符串,这样我们没有办法来设置
这个cookie的相关属性的值,例如它的路径,生命时长等。
*/
//快捷方式:直接调用getCookies(),这样就会返回cookie数组
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie c : cookies){
out.println(c.getName() + " = " + c.getValue() +
",path = " + c.getPath() +
",maxAge = " + c.getMaxAge() + "<br/>");
}
}
%>
</body>
</html>
测试结果:
但是值得注意的是,如果我们添加的cookie的值是中文,那么这时候会发生500错误。例如下面我们a.jsp中为:
Cookie cookie1 = new Cookie("aaa", "小A");
response.addCookie(cookie1);
Cookie cookie2 = new Cookie("bbb", "小B");
response.addCookie(cookie2);
访问localhost:8080/cookie1/a.jsp,就会出现下面的错误:
cookie的生命时长可以通过setMaxAge(second)来设置,其中生命时长是以秒为单位的。其中second值得情况不同,cookie的生命时长不同。默认情况下(即没有设置cookie生命时长),cookie是在浏览器关闭之后就会失效的。
- second > 0,cookie保存到了客户端的硬盘中,生命时长为second。
- second < 0,那么cookie保存到了浏览器的内存中,一旦退出了浏览器,那么这个cookie就失效了
- second = 0,那么此时的cookie立刻失效。再次查看它的请求头Cookie时,就不会存在这个cookie了。
值得一提的是,尽管我们已经设置了cookie的生命时长,但是最后调用getMaxAge()来输出的时候却是-1.xu要我们在浏览器中的特定位置查看才可以。以必应为例,我们需要点击设置->cookie和网站权限->管理和删除cookie和站点数据->查看所有Cookie和站点数据->找到自己对应的cookie.
正如下面代码中我们设置aaa的生命时长为1小时:
<!--这是cookie2下面的a.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>设置cookie的生命时长</title>
</head>
<body>
<h1>设置cookie的生命时长</h1>
<%
//调用addCookie来添加cookie
Cookie cookie1 = new Cookie("aaa", "AAA");//创建名字为aaa的cookie,对应的值为AAA
//调用setMaxAge(second)来设置cookie的生命时长,以秒为单位
/*
设置生命时长为0,那么下面虽然能将当前这个cookie添加到响应头中,
但是在获取请求头Cookie的值中并没有此时添加的cookie,因为它已经失效了
cookie1.setMaxAge(0);
*/
cookie1.setMaxAge(60 * 60);
response.addCookie(cookie1);//调用addCookie添加cookie,此时响应头Set-Cookie,就会出现这个cookie
%>
</body>
</html>
<!--这是cookie2下面的b.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>获取cookie的生命时长</title>
</head>
<body>
<h1>获取cookie的生命时长</h1>
<%
Cookie[] cookies = request.getCookies();
for(Cookie cookie: cookies){
/*
cookie的时长:
不能通过getMaxAge()来访问,否则,最后输出的是-1,因此我们要通过浏览器
来看,例如以必应为例,点击设置->cookie和网站权限->管理和删除cookie数据
->查看所有的cookie和站点数据.
进行这一步之前,需要将所有的cookie数据删除,然后在测试,这样就能很快找到
当前运行的cookie数据。然后点击对应名字的cookie,就可以查看它的路径和生命时长了
*/
out.println(cookie.getName() + ", value = " + cookie.getValue() +
", maxAge = " + cookie.getMaxAge() + "<br>");
}
%>
</body>
</html>
测试结果:
⭐注意,设置cookie的时长,需要保证它是在addCookie之前设置的,否则如果先写addCookie,然后再设置cookie的时长,那么setMaxAge是没有生效的,此时cookie是在浏览器关闭之后就会失效的。以上面cookie2下面的a.jsp中的代码为例:
⭐只要当前地址栏中的URL包括了cookie的路径,那么请求头Cookie就会带有响应的cookie。正如上面的,我们点击cookie2下面的b.jsp,那么请求头中就包括了aaa这个cookie。
而JSESSIONID的路径是/,所以始终会带有这个cookie。
Session:是客户端和服务端的一次会话过程,当会话结束或者这个session失效了,那么这个session就失效了。session是保存在服务端中。
而获取session,如果在Servlet中,可以根据request.getSession()来获取HttpSession对象,而在JSP中,session是它的内置对象,所以我们可以直接使用。
Session也是一个域对象(request,session,application是三大域对象),都含有getAttribute(target),setAttribute(target,value),removeAttribute(target)这三个方法。这三个方法是常用的主要方法。但是在session中,还有几个常用的方法:
- void invalidate():使当前的session失效,可以用于用户退出登录,当下次再次请求的时候需要重新登录了。
- String getSessionId():获取sessionId
- boolean isNew():判断当前的session是否是新建的。
- int getMaxInactiveInternal():获取当前sssion最大的不活动时间(秒),默认是30分钟.可以在web.xml中设置session的最大不活动时间:
理解request.getSession()方法:
-> 客户端如果是第一次来访问服务端,那么就会创建session,并且将对应的sessionId发送给客户端
-> 当下次客户端再次发送请求的时候,会携带sessionId,那么服务端就会根据sessionId来查找session,
如果不能找到session,那么服务端就会再新建session,然后再将新的sessionId返回给客户端;否则如果能够找到session,那么就不需要再新建session。
练习: 利用session以及cookie来实现登录界面,要求如下:
所以解题思路:
- 创建login.jsp,success1.jsp,success2.jsp这几个文件,并且显示对应的页面。
- 创建LoginServlet类,用于处理数据。
- 在LoginServlet类中,首先获取login.jsp传来的数据,考虑到参数的值可能是中文,那么需要进行解码。此时请求编码,并且是post请求,所以直接调用setCharacterEncoding来设置编码即可。
- 然后判断用户名和密码是否正确,如果不正确,那么利用request域对象,调用setAttribute,来设置错误的提示信息,然后转发到login.jsp中(不可以是重定向,否则,在login.jsp中不可以利用request来获取提示信息)
- 否则,如果用户名和密码都正确,那么就需要保存当前登录的用户名保存到session中,这样就可以在success1.jsp中利用session调用getAttribute来获取登录用户了。
- 如果没有登录,直接访问success1.jsp,那么需要利用是否存在session来判断是否已经有用户登录了,如果没有,那么就设置对应的提示信息,并将提示信息转发到login.jsp中.
LoginServlet类:
public class LoginServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//判断是否登录成功
//对于客户端编码,我们需要利用request直接调用setCharacterEncoding即可
request.setCharacterEncoding("utf-8");
String name = request.getParameter("name");
String password = request.getParameter("password");
//判断用户名或者密码是否为空
if(name == null || "".equals(name)){
//说明用户名没有写就提交了登录按钮
request.setAttribute("msg","用户名为空!!!");
//转发到login.jsp页面
request.getRequestDispatcher("/session/login.jsp").
forward(request,response);
}
if(password == null || "".equals(password)){
//说明用户名没有写就提交了登录按钮
request.setAttribute("msg","密码为空!!!");
//转发到login.jsp页面
request.getRequestDispatcher("/session/login.jsp").
forward(request,response);
}
//判断用户名和密码是否正确
if("张三".equals(name) && "123456".equals(password)){
/*
密码正确,然后重定向到success1.jsp页面,并且将用户名保存到session中
之所以要保存到session中,是因为session是在一次会话中的,只要没有关闭服务
器,那么就可以这个session就一直存在,这样我们跳转到其他的页面,都可以
利用session来获取用户名。
如果我们使用的是request来保存name这个属性,那么就不可以利用重定向来跳转
到success1.jsp中,因为此时的重定向是重新发送请求的,所以如果利用的是request,
那么需要不断进行请求转发,但是地址栏上依旧是当前页面的url,显然并不符合实际开发.
request.setAttribute("name",name);
request.getRequestDispatcher("/session/success1.jsp")
.forward(request,response);
*/
/*
添加cookie,从而如果之前没有登录过,那么添加cookie,记住当前的用户
然后在cookie失效之前,每次登录,都可以在文本框中显示登录用户的名字
*/
Cookie cookie = new Cookie("username", URLEncoder.encode(name,"utf-8"));
/*
设置当前cookie时长为1小时,注意这个语句需要在addCookie执行之前执行
否则,如果是下面那样,那么就会导致cookie存入到了浏览器内存中,当浏览器
关闭的时候,这个cookie就失效了
response.addCookie(cookie);
cookie.setMaxAge(60 * 60);
*/
response.addCookie(cookie);
HttpSession session = request.getSession();
session.setAttribute("name",name);
//重定向到success1.jsp中,从而使得地址栏发生了变化
response.sendRedirect("/session/success1.jsp");
}else{
//设置提示信息,表示用户名或者密码错误
request.setAttribute("msg","用户名或者密码错误");
//重新跳转到login.jsp中
request.getRequestDispatcher("/session/login.jsp")
.forward(request,response);
}
}
}
login.jsp、succes1.jsp、success2.jsp:
<!--login.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录界面</title>
</head>
<body>
<span style="color: red;">
<b>
<!--获取错误的提示信息,如果提示信息为空,说明是第一次访问,否则是登录失败-->
<%=request.getAttribute("msg") == null ? "" : request.getAttribute("msg")%>
</b>
</span>
<%
String username = "";
//获取cookie请求头
Cookie[] cookies = request.getCookies();
if(cookies != null){
for(Cookie cookie : cookies){
if("username".equals(cookie.getName())){
//因为登录用户的值可能是中文,所以需要进行解码
username = URLDecoder.decode(cookie.getValue(),"utf-8");
break;
}
}
}
%>
<form action="/LoginServlet" method="post">
姓 名: <input type="text" name="name" value="<%=username%>"><br>
密 码: <input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
<!--success1.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功登录的界面1</title>
</head>
<body>
<%
/*
首先从session中获取name这个参数的值,如果为空,说明没有登录,需要
转发到login.jsp中,否则,如果不为空,那么直接赋值给user
*/
String user = "";
String name = (String)session.getAttribute("name");
if(name == null){
//如果为空,那么需要将对应的提示信息报存到request域中,然后转发到login页面
request.setAttribute("msg","没有权限,请先登录");
request.getRequestDispatcher("/session/login.jsp")
.forward(request,response);
return;//通过这个,那么剩下的所有代码不会执行了,
}else{
user = name;
}
%>
<h1>成功登录的界面</h1>
您好,<%=user%>
</body>
</html>
<!--success2.jsp-->
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>成功登录之后的界面2</title>
</head>
<body>
<%
/*
同样的,如果没有登录,就来访问这个页面,需要重新跳转到login.jsp页面
但是因为需要利用request域来保存提示信息,如果利用的是重定向的话,那么
没有办法看到提示信息,所以需要利用的是请求转发
*/
String user = "";
String name = (String)session.getAttribute("name");
if(name == null){
//如果name的值为空,说明还没有登录,需要转发到login页面
request.setAttribute("msg","没有权限,请先登录");
request.getRequestDispatcher("/session/login.jsp")
.forward(request,response);
return;
}else{
user = name;
}
%>
<h1>成功登录后的界面2</h1>
您好,<%=user%>
</body>
</html>