背景
- 客户端要跟Java通信,只能通过servlet
- 如果要返回一个html页面,只能在doGet()方法里,只能一行行写write(),很繁琐
- 为了解决上述问题,有了JSP
- JSP解译成Java文件后,源码其实也是一行行out.write()
什么是JSP
- 本质:就是一个servlet(Java也只能处理Servlet)
- 负责与用户交互,将最终界面呈现给用户
- 静 —— > 动
- HTML+CSS+JS+Java的混合文件
- Java的代码负责数据处理的部分
- 转换过程:JSP —— Java程序 —— class字节码文件
工作机制
- 当服务器收到一个后缀是.jsp的请求时,将该请求交给JSP引擎去处理
- 每一个JSP文件第一次被访问的时候,JSP引擎会把它翻译成一个Servlet文件,再由Web容器来调用Servlet完成响应
嵌入方式
-
从开发角度看:JSP = HTML 嵌入 Java代码
-
具体方式:
- JSP 脚本:执行Java逻辑代码
<% //Java代码,只能调方法 String str = "Hello"; System.out.println(str); // 在控制台输出!! System.out.println(test()); %>
- JSP 声明:定义方法
<%! //声明Java方法 public String test(){ return "Hello"; } %>
- JSP 表达式:把Java对象直接输出到HTML页面上
<%=str%>
-
代码整合
<%!
public String test(){
return "Hello";
}
%>
<%
String str = test();
%>
<%=str%>
- 循环怎么写
<%
for(int i=0;i<names.size();i++){
%>
<tr>
<td>
<%=names.get(i)%>
</td>
<td>
<%=ages.get(i)%>
</td>
</tr>
<%
}
%>
- 本质:<% %>内的直接转成Java代码,外面的会翻译成Java代码,并调用write()
九个内置对象
-
内置:不用去调,直接用就好
-
原理:JSP的代码会被拷贝到service()里面,而service()的对象已经创建好了或传进来了,可以直接用
-
request:表示一次请求,HttpServletRequest
-
response:表示一次响应,HttpServletResponse
-
pageContext:页面上下文【全局对象】,获取页面信息,pageContext
-
session:表示一次会话,保存用户信息,HttpSession
-
application:表示当前web应用【全局对象】,保存所有用户共享信息,ServletContext
-
config:当前JSP对应的Servlet的ServletConfig对象,获取当前Servlet的信息
-
out:像浏览器输出数据,JSPWriter
-
page:当前JSP对应的servlet对象,Servlet
-
exception:表示JSP页面发生的异常,Exception
request常用方法
- getParameter()【服务器与客户端之间传递】
// 获取客户端传来的参数,通过key取value
// eg.?id=1&name=wq 都是String类,根据需要转
String getParameter(String key);
// 转型
Integer id = Integer.parseInt(idStr);
Double score = Double.parseDouble(scoreStr);
// 在JSP中使用
<%
String id = request.getParameter("id");
%>
<%=id%>
-
void setAttribute(String key,Object value) 通过键值对的形式来保存数据【服务器内部传递】
-
Object getAttribute(String key) 通过key取出value
-
RequestDispatcher getRequestDispatcher(String path) 主要是用该对象的forward()方法转发请求
/* 以下代码写在test1.jsp中 */
// 将数据存入request中
request.setAttribute("number",id);
// 将请求转发给test2.jsp:生成目的地,再出发
request.getRequestDispatcher("test2.jsp").forward(request,response);
/* 以下代码写在test2.jsp中 */
Integer number = (Integer)request.getAttribute("number");
/* 如果请求转发了,做响应的是test2,如果没转,就是test1;同理,最后的目的地是哪,响应的就是哪个对象 */
-
String[] getParameterValues() 解决“如果同时传了多个相同key的参数,只保存第一个”,获取客户端传来的多个同名参数
-
void setCharacterEncoding(String charset) 指定请求的编码,处理中文乱码
HTTP状态码
- 200:正常
- 404:资源找不到
- 400 :请求类型不匹配
- 500:Java程序抛出异常
response常用方法
-
sendRedirect(String path) 重定向,页面之间的跳转
- 转发 getRequestDispatcher和重定向sendRedirect的区别:
- 转发是将同一个请求传给下一个页面;重定向是创一个新请求传给下一个页面,之前的请求结束生命周期
- 前者拿得到数据,后者拿不到
- 转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转
- 重定向:由客户端发送一次新请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转
- 如果两个页面之间需要通过request来传值,必须使用转发,不能重定向
- 转发 getRequestDispatcher和重定向sendRedirect的区别:
-
应用:用户登录。如果用户名和密码正确,则跳转到首页(转发),并且展示用户名,否则重新回到登陆页面(重定向)
-
login.jsp——登录页面,提交表单
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
</head>
<body>
<form action="/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
<input type="reset" value="重置">
</form>
</body>
</html>
- LoginServlet.java——处理登录表单(纯Java代码不要写在JSP)
package com.microsoft.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
private String myUsername;
private String myPassword;
@Override
public void init(ServletConfig config) throws ServletException {
// 如果传入参数有myUsername、myPassword,就要this
myUsername = config.getInitParameter("username");
myPassword = config.getInitParameter("password");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username.equals(myUsername) && password.equals(myPassword)){
// 登录成功——转发
req.setAttribute("username",username);
req.getRequestDispatcher("welcome.jsp").forward(req,resp);
}else{
// 登录失败——重定向
resp.sendRedirect("fail.jsp");
}
}
}
- welcome.jsp——登录成功页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>welcome</title>
</head>
<body>
<h1>登录成功!</h1><br>
<%
String username = (String) request.getAttribute("username");
%>
欢迎回来,<%=username%>
</body>
</html>
- fail.jsp——登录失败页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>fail</title>
</head>
<body>
<h1>登录失败!</h1><br>
<form action="/login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
<input type="reset" value="重置">
</form>
</body>
</html>
- web.xml 配置用户信息
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.microsoft.servlet.LoginServlet</servlet-class>
<init-param>
<param-name>username</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
- 存在问题:用户新开一个页面进入welcome.jsp,就变成null对象了(原因request生命周期太短,需要引入session)
Session
-
用户会话
-
问题:服务器无法识别每一次HTTP请求的出处(不知道来自哪个终端),它只会接收到一个请求信号,有可能将用户的响应给其他人
-
会话:客户端和服务器之间发生的一系列连续的请求和响应的过程 ,打开浏览器进行操作到关闭浏览器的过程
-
会话状态:指服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同一次会话的一系列请求和响应关联起来(SessionID)
-
属于同一次会话的请求都有一个相同的标识符——SessionID
- String类型的session.getId()
- 即使同一终端,浏览器不同,id就会不同
- 十六进制
session常用方法
-
String getId() 获取SessionID
-
void setMaxInactiveInterval(int interval) 设置session的失效时间(单位:s)
-
int getMaxInactiveInterval() 获取当前session的失效时间
-
void invalidate() 设置session立即失效
【上面三个配合使用,定时,查看,失效】
-
void setAttribute(String key,Object value) 通过键值对的形式来保存数据
- 没有,添加【增】
- 有,修改【改】
-
Object getAttribute(String key) 通过key取出value【查】
-
void removeAttribute(String key) 通过key删除value【删】
- request也有,但不要用,request本身生命周期短,但session不一样
-
解决上面“用户登录”问题 —— 拓展作用域以及功能完善
-
更改LoginServlet.java的doPost()部分——都用重定向
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
if(username.equals(myUsername) && password.equals(myPassword)){
HttpSession session = req.getSession();
session.setAttribute("username",username);
// 登录成功——重定向,用session跟转发没半毛钱关系
resp.sendRedirect("welcome.jsp");
}else{
// 登录失败——重定向
resp.sendRedirect("fail.jsp");
}
}
- 更改welcome.jsp —— 避免未登录直接访问以及session的调试
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>welcome</title>
</head>
<body>
<%
String username = (String) session.getAttribute("username");
if (username != null){
%>
<h1>登录成功!</h1><br>
欢迎回来,<%=username%><br>
<a href="/logout">注销账户</a>
<%
}
else{
%>
<h1>宁还没登录呢</h1><br>
<a href="/login.jsp">登录</a>
<%
}
%>
</body>
</html>
- 添加类LogoutServlet.java——新增注销功能
package com.microsoft.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// <a>是GET方法
HttpSession session = req.getSession();
// 销毁,注销用户
session.invalidate();
// 跳转到login页面
resp.sendRedirect("login.jsp");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
Cookie
-
不是内置对象
-
本质:一个记录用户信息的文件,保存在浏览器内
-
第一次访问某网页的HTTP响应,浏览器会给用户cookie
-
传递过程
- 请求:客户端 ——> 服务器
- 响应:服务器 ——> 客户端
-
cookie对象是个键值对
- 在请求响应的头中:Cookie:key1=value1;key2=value2;key3=value3
Cookie常用方法
- response.addCookie(cookie) 增加cookie
- request.getCookies() 拿回来全部cookie
- cookie.getName() 拿键
- cookie.getValue() 拿值
- void setMaxAge(int age) 设置cookie有效时间(单位:s)
- 默认值是-1,一关就没了
Session和Cookie的区别
-
session:
-
JSP内本身就存在
-
Java提供,在服务器存储用户信息【存在JVM内存中】
-
保存的数据是Object
-
生命周期:随着会话的结束而销毁
-
保存重要信息 eg.账号密码
-
-
cookie
-
要自己new一个
-
浏览器提供,在客户端存储用户信息
-
保存的数据是String
-
生命周期:与会话无关,可以长期存在浏览器中,关机也还在
-
保存不重要信息 eg.视频播放记录
-
-
二者的存取
// Session存
session.setAttribute("username",username);
// Session取
String username = (String) session.getAttribute("username");
// Cookie存
response.addCookie(new Cookie(username,"admin"));
// Cookie取
Cookie[] cookies = request.getCookies();
for(Cookie cookie:cookies){
if(cookie.getName().equals("name")){
out.write("欢迎回来,"+cookie.getValue());
}
}
- 二者退出登录
// session
session.invalidate();
// cookie
cookie.setMaxAge(0)
作用域
-
setAttribute()、getAttribute()
-
page作用域:对应的内置对象是pageContext,当前页面有效(没有实际开发意义)
-
request作用域:对应的内置对象是request,在一次请求内有效(再开一个新网页就不行了)
-
session作用域:对应的内置对象是session,在一次会话内有效(多次请求)
-
application作用域:对应的内置对象是application,对整个web应用有效(跨浏览器,跨主机,存在Tomcat里的)
-
大小比较:page<request<session<application
-
应用:网站访问量统计【一般会在服务器关闭时,把count存入数据库】
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>首页</title>
</head>
<body>
<h1>首页</h1><br>
<%
Integer count = (Integer) application.getAttribute("count");
if(count == null){
count = 1;
application.setAttribute("count",count);
}else{
count++;
application.setAttribute("count",count);
}
%>
<p>这是宁第<%=count%>次访问</p><br>
<a href="login.jsp">还没登录吗?点我</a>
</body>
</html>