2.JSP篇
本文章基于B站UP主:楠哥教你学Java 的课程《Java Web从入门到实战【完整版】》进行整理补充,本文章仅用于个人学习交流使用。1.JSP实质
JSP本质上就是一个Servlet,JSP主要负责与用户交互,将网页最终的界面呈现给用户,就是 HTML + CSS + JS + Java
当服务器接收到⼀个后缀是 jsp 的请求时,将该请求交给 JSP 引擎去处理,每⼀个 JSP ⻚⾯第⼀次被访问的时候, JSP 引擎会将它翻译成⼀个 Servlet ⽂件,再由 Web 容器调⽤ Servlet 完成响应。
单纯从开发的⻆度看, JSP 就是在 HTML 中嵌⼊ Java 程序
1.用 Servlet 方法实现 JSP
其实就是将JSP代码一行一行输出,然后被网页解析为HTML并显示
2.打开本地编译后的JSP
例如:index_jsp.java 文件
其实JSP就是自动完成了代码的转化
2.JSP嵌入
具体的嵌入方式有三种
- JSP脚本:执行 Java 逻辑代码
<% java代码 %>
- JSP声明:定义 java 方法
<%!
声明 Java 方法
%>
- JSP表达式:把 Java 对象直接输出到页面中
<%=
Java变量
%>
直接写变量,后面不用写 分号 ;
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<h1>Hello</h1>
<h2>world</h2>
<%!
public String test(){
return "Hello World 002";
}
%>
<%
String str="HelloWorld001";
System.out.println(str);//控制台输出
String str2=test();
System.out.println(str2);
%>
<%=
str2
%>
</body>
</html>
网页界面:
![](https://i-blog.csdnimg.cn/blog_migrate/8b6903a2014576556822e47038e7e3af.png)
控制台界面:
因不明原因,多输出了几次,等待后续研究
![](https://i-blog.csdnimg.cn/blog_migrate/d45cd913183cf8585cd5298ad84ec8a0.png)
案例:JSP输出一个表格
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %><%--
Created by IntelliJ IDEA.
User: DELL
Date: 2020/3/23
Time: 21:03
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
List<String> names=new ArrayList<>();
names.add("张三");
names.add("李四");
names.add("王五");
List<Integer> ages=new ArrayList<>();
ages.add(22);
ages.add(24);
ages.add(25);
%>
<table border="1">
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<!--方法一:直接挨个输出
<tr>
<td><%=names.get(0)%></td>
<td><%=ages.get(0)%></td>
</tr>
-->
<!--用Java里面的for循环结构-->
<%
for (int i=0;i<names.size();i++){
%>
<tr>
<td><%=names.get(i)%></td>
<td><%=ages.get(i)%></td>
</tr>
<%
}
%>
</table>
</body>
</html>
用 面向对象思想 , 实体类,进一步优化。
User.java
package com.lut.entity;
public class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
//带参构造
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}
index.jsp
<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.lut.entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>$Title$</title>
</head>
<body>
<%
List<User> list=new ArrayList<>();
list.add(new User("张三",21));
list.add(new User("李四",22));
list.add(new User("王五",23));
%>
<table border="1">
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<%
for (int i=0;i<list.size();i++){
%>
<tr>
<td><%=list.get(i).getName()%></td>
<td><%=list.get(i).getAge()%></td>
</tr>
<%
}
%>
</table>
</body>
</html>
如果用 list.get(i) 方法获得的是对象
3.JSP内置对象
内置对象直接使用,不需要去创建,因为将JSP转化为Servlet时,系统已经自动创建好了对象。
一共有9个,但并不是都常用,但需要都了解
request 表示一次请求 由 HttpServletRequest 类产生
response 表示一次响应 HttpServletResponse
pageContext 页面上下文(整体),获取页面信息 PageContext
session 表示一次会话,保存用户信息 HttpSession
application 表示当前Web应用,全局对象,保存所有用户共享信息 ServletContext
config 当前JSP对应的 Servlet 的 ServletConfig 对象,获取当前Servlet信息
out 向浏览器输出数据 jspWrite
page 当前JSP对应的 Servlet 对象 Servlet
exception 表示JSP页面发生的异常 Exception
···
常用的:request,response,session,application,pageContext
···
request常用方法
1、String getParameter(String key) 获取客户端传来的参数
2、 void setAttribute(String key,Object value) 通过键值对的形式保存数据。
3、 Object getAttribute(String key) 通过 key 取出 value。
(2和3 服务器内部之间,多个JSP之间进行数据传递)
(1.getParameter 从浏览器到服务器之间的信息传递)
test01.jsp
<body>
<%
String idStr=request.getParameter("id");//地址栏后面加 ?id=123
Integer id=Integer.parseInt(idStr);
id++;
//将数据存入到request中
request.setAttribute("number",id);
//将请求转发给test2.jsp
request.getRequestDispatcher("text2.jsp").forward(request,response);
%>
<h1>text01.jsp</h1>
<%=id%>
</body>
test02.jsp
<body>
<%
Integer number=(Integer) request.getAttribute("number");
%>
<h1>text02.jsp</h1>
<%=number%>
</body>
**注:**地址栏仍然为 text01.jsp 但在text01.jsp的内部已经实现跳转到了 text02.jsp
4、 RequestDispatcher getRequestDispatcher(String path) 返回⼀个 RequestDispatcher 对象,该对象的 forward ⽅法⽤于请求转发。
5、 String[] getParameterValues() 获取客户端传来的多个同名参数。
(地址栏输入:?name=tom&name=catt&name=jack)
<body>
<%
String[] names=request.getParameterValues("name");
%>
<!--Arrays.toString(names)获取names数组中所有元素并拼接在一起--[tom, catt,jack]-->
<%=Arrays.toString(names)%>
</body>
6、 void setCharacterEncoding(String charset) 指定每个请求的编码。
request.setCharacterEncoding("UTF-8");
response常用方法
1、 sendRedirect(String path) 重定向,⻚⾯之间的跳转。
<body>
<h1>Test01</h1>
<%
request.setAttribute("name","Tom");
//request.getRequestDispatcher("test02.jsp").forward(request,response);
response.sendRedirect("test02.jsp");//用这种方法并不能传递数据
%>
</body>
<body>
<h1>text02.jsp</h1>
<%
String name=(String)request.getAttribute("name");
out.write(name);
%>
<!--能够正常跳转,但并不能正常显示out.write()会报空指针异常 -->
</body>
转发 getRequestDispatcher 和 重定向 sendRedirect 的区别:
转发是将同⼀个请求传给下⼀个⻚⾯,
重定向是创建⼀个新的请求传给下⼀个⻚⾯,之前的请求结束⽣命周期。
转发:同⼀个请求在服务器之间传递,地址栏不变,也叫服务器跳转。
重定向:由客户端发送⼀次新的请求来访问跳转后的⽬标资源,地址栏改变,也叫客户端跳转。
如果两个⻚⾯之间需要通过 request 来传值,则必须使⽤转发,不能使⽤重定向。
**案例:**实现⽤户登录,如果⽤户名和密码正确,则跳转到⾸⻚(转发)并且展示⽤户名,否则重新回到登陆⻚⾯(重定向)。
- 登录界面:主要作用:外观展示—login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录页面</title>
</head>
<form action="/check.jsp" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td><input type="submit" value="登录"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</form>
</html>
- 获取信息和核对信息的界面—check.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<!--接受用户输入的信息-->
<%
String username=request.getParameter("username");
String password=request.getParameter("password");
//假设用户名为 admin 密码为123456
if(username.equals("admin")&& password.equals("123456")){
//登录成功
request.setAttribute("name",username);
request.getRequestDispatcher("welcome.jsp").forward(request,response);
}else{
//登录失败//用转发和重定向都可以
response.sendRedirect("login.jsp");
}
%>
</body>
</html>
- 欢迎界面,登录成功后显示—welcome.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<%
String name=(String)request.getAttribute("name");
%>
欢迎回来!<%=name%>
</body>
</html>
最终页面:
session常用方法
主要作用:完成用户会话
服务器⽆法识别每⼀次 HTTP 请求的出处(不知道来⾃于哪个终端),它只会接受到⼀个请求信号,所以就存在⼀个问题(将⽤户的响应发送给其他⼈),必须有⼀种技术来让服务器知道请求来⾃哪,这就是会话技术。
一次会话:就是客户端和服务器之间发⽣的⼀系列连续的请求和响应的过程,打开浏览器进⾏操作到关闭浏览器的过程。
会话状态:指服务器和浏览器在会话过程中产⽣的状态信息,借助于会话状态,服务器能够把属于同⼀次会话的⼀系列请求和响应关联起来。
<body>
<%
String sessionId=session.getId();
%>
<%=sessionId%>
<!--使用out.write()若果是空值会抛异常-->
</body>
不同的浏览器会获得不同的sessionid,每一个浏览器都是一次单独的会话
-谷歌浏览器
![](https://i-blog.csdnimg.cn/blog_migrate/8a033d6be252d52cb7e97c0e5f5e77bc.png)
-QQ浏览器
![](https://i-blog.csdnimg.cn/blog_migrate/f5324e70d0321514ca897b005cbfb943.png)
即便是相同的浏览器,关闭后重新打开又是不同的sessionid,即是不同的会话
-第二次打开谷歌浏览器
![](https://i-blog.csdnimg.cn/blog_migrate/2049ed678f7d2e42c160c0f8da512f41.png)
session 常⽤的⽅法:
String getId() 获取 sessionID
void setMaxInactiveInterval(int interval) 设置 session 的失效时间,单位为秒
(短时间内登陆不用重复输入账号密码,7day)
int getMaxInactiveInterval() 获取当前 session 的失效时间
void invalidate() 设置 session ⽴即失效
void setAttribute(String key,Object value) 通过键值对的形式来存储数据
Object getAttribute(String key) 通过键获取对应的数据
void removeAttribute(String key) 通过键删除对应的数据
案例: 实现⽤户登录,如果⽤户名和密码正确,则跳转到首页并且展示⽤户名,否则重新回到登陆。登陆成功后,在浏览器不关闭的情况下,直接访问session会展示用户名(session),实现退出功能,即再次访问主页不会显示用户名。
注: 在上一个同类型案例中,check.jsp 文件中只用到了java代码,却使用的是 .jsp 文件,并不符合开发规范,这次我们使用 servlet 实现核对功能。
- 登陆界面—login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/login" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td><input type="submit" value="登录"></td>
<td><input type="reset" value="重置"></td>
</tr>
</table>
</form>
</body>
</html>
- 信息核对界面—在 com.lut.sessiom目录下面—LoginServlet.java
package com.lut.session;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginServlet extends HttpServlet {
private String myusername;
private String mypassword;
@Override
public void init(ServletConfig config) throws ServletException {
//XML里面的值
myusername=config.getInitParameter("username");
mypassword=config.getInitParameter("password");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
}
@Override
//在login.jsp 文件中的 标签<form action="/login" method="post">
//声明了请求类型位 post ,所以在 doPose里面实现
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//JSP文本框里面的值
String username=req.getParameter("username");
String password=req.getParameter("password");
//将用户名密码定义为初始化参数,这样不能用注解映射,用XML映射
if(username.equals(myusername) && password.equals(mypassword) ){
//用Session保存用户名和密码
HttpSession session=req.getSession();
session.setAttribute("username",username);
req.getRequestDispatcher("welcome.jsp").forward(req,resp);
/* 不用 session 直接 req
req.setAttribute("username",username);
req.getRequestDispatcher("welcome.jsp").forward(req,resp);*/
}else {
//重定向
resp.sendRedirect("login.jsp");
}
}
}
注: 在这里,获取正确的用户名和密码的方式是:将用户名和密码初始化为参数,即从XML文件里面获取,用MXL实现映射关系。
- XML文件,实现映射关系—web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>com.lut.session.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>login</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
</web-app>
- 主页—显示用户成功登陆后的信息—welcome.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>Welcome</h1>
<!--欢迎回来<%=request.getAttribute("username")%>--从request里面取-->
<!--从session里面取,因为在LoginServlet.java是用session发送的信息-->
欢迎回来<%=session.getAttribute("username")%>
<a href="logout">退出</a><!--退出,销毁session-->
</body>
</html>
- 退出功能—在 com.lut.sessiom目录下面—LogoutServlet.java
package com.lut.session;
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
//a标签的请求类型是 get ,所以在 doGet 里面实现
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session=req.getSession();
session.invalidate();//立即失效
resp.sendRedirect("login.jsp");//回到登录页面
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
}
界面显示:
登陆界面
![](https://i-blog.csdnimg.cn/blog_migrate/258e8b37c8f7a08a8ca56f6f69cdf3f7.png)
欢迎界面:
![](https://i-blog.csdnimg.cn/blog_migrate/a8c6f2407d5406a95e1df65e942ee899.png)
存在问题,如果不使用session,登陆成功后,并退出欢迎界面,(不关闭浏览器),再次回到欢迎界面时(手敲地址访问),并不显示用户信息,如下图所示:
![](https://i-blog.csdnimg.cn/blog_migrate/de27a84d35a18e43bd809d065dabfb96.png)
使用session进行改进,(旧的代码已经在源代码中注释),主要在LoginServlet.java里面使用session发送信息,在welcome.jsp里面用sesison接受信息。
修改后,登陆成功后,并退出欢迎界面,(不关闭浏览器),再次回到欢迎界面时,成功显示用户信息。点击“退出登录”,或关闭浏览器,再次回到欢迎界面时(手敲地址访问),并不会显示用户信息。
额外补充:
HTTP 请求状态码
200:正常
404:资源找不到
400:请求类型不匹配
500: Java 程序抛出异常
4.JSP内置对象的作用域
在这里我们仅讨论4个
page、 request、 session、 application
因为它们都具有:setAttribute、 getAttribute 方法
page 作⽤域:对应的内置对象是 pageContext。
request 作⽤域:对应的内置对象是 request。
session 作⽤域:对应的内置对象是 session。
application 作⽤域:对应的内置对象是 application。
范围大小:page < request < session < application
page 只在当前⻚⾯有效。
<body>
<%
pageContext.setAttribute("name","Tom");
%>
<h1>pageContext</h1>
<%
String name=(String) pageContext.getAttribute("name");
out.write(name);
%>
</body>
request 在⼀次请求内有效。
session 在⼀次会话内有效。
application 对应整个 WEB 应⽤的。
只要tomcat不关闭,关闭浏览器,其他浏览器均可访问
案例:网站的访问量统计
当刷新浏览器或更换浏览器访问时,次数会增加
<%
Integer count=(Integer)application.getAttribute("count");
if (count==null){
count=1;
application.setAttribute("count",count);
}else{
count++;
application.setAttribute("count",count);
}
%>
你是当前的第<%=count%>访客。