JavaWeb学习笔记
笔记可参考链接:https://www.yuque.com/csy/ykokl4/gg7vty
互联网通信
一、关于系统架构
C/S结构
优点:
1.速度快,体验好,界面炫酷(大量的数据都是集成在客户端软件当中,所以服务器只需要传送很少的数据量)
2.服务器压力小(大量的数据都是集成在客户端软件当中,所以服务器只需要传送很少的数据量)
3.安全(大量的数据都是集成在客户端软件当中,数据在多个客户端上有缓存)
缺点:
升级维护比较差劲(每一个客户端都需要升级)
B/S架构
优点:
升级维护方便,成本比较低。(只需要升级服务器端即可。)
不需要安装特定的客户端软件,只需要打开浏览器,输入网址即可。
缺点:
速度慢(因为所有的数据都是在服务器上,用户发送的每一个请求都是需要服务器全身心的响应数据)
不安全
二、 B/S结构的系统通信原理
2.1域名
https://www.baidu.com/(网站),www.baidu.com 是一个域名
在浏览器地址栏上输入域名,回车之后,域名解析器会将域名解析出来一个具体的IP地址和端口号等。
解析结果也许是:http://110.242.68.3:80/index.html
IP地址: 一台主机的身份证号
端口号: 一个软件
2.2一个WEB系统的通信原理?
● 第一步:用户输入网址(URL)
● 域名解析器进行域名解析:110.242.68.3:80/index.html
● 浏览器软件在网络中搜索并找到110.242.68.3这一台主机
● 该台主机定位到80端口对应的服务器软件
● 80端口对应的服务器软件得知浏览器想要的资源名是:index.html
● 服务器软件找到index.html文件,并且将index.html文件中的内容直接输出响应到浏览器上。
● 浏览器接收并执行到来自服务器的代码(HTML CSS JS)
2.3模拟Servlet的本质
● 充当SUN公司的角色,制定Servlet规范
○ javax.servlet.Servlet接口
● 充当Webapp的开发者
○ BankServlet implements Servlet
○ UserListServlet implements Servlet
○ UserLoginServlet implements Servlet
● 充当Tomcat服务器的开发者
package javax.servlet;
/*
我们现在充当的角色是SUN公司,
SUN公司把Servlet接口/规范制定出来了
*/
public interface Servlet {
//一个专门提供服务的方法.
void service();
}
package com.bjpowernode.servlet;
import javax.servlet.Servlet;
public class BankServlet implements Servlet {
@Override
public void service() {
System.out.println("BankServlet is servce...");
}
}
package com.bjpowernode.servlet;
import javax.servlet.Servlet;
public class UserListServlet implements Servlet {
@Override
public void service() {
System.out.println("UserListServlet is servce...");
}
}
package com.bjpowernode.servlet;
import javax.servlet.Servlet;
public class UserLoginServlet implements Servlet {
@Override
public void service() {
System.out.println("UserLoginServlet is servce...");
}
}
package org.apache;
import java.util.Scanner;
import java.util.Properties;
import java.io.FileReader;
import javax.servlet.Servlet;
// 充当Tomcat服务器的开发者
public class Tomcat{
public static void main(String[] args) throws Exception{
System.out.println("Tomcat服务器启动成功,开始接收用户的访问。");
// 简单的使用Scanner来模拟一下用户的请求
// 用户访问服务器是通过浏览器上的“请求路径”
// 也就是说用户请求路径不同,后台执行的Servlet不同。
/*
/userList UserListServlet
/login UserLoginServlet
/bank BankServlet
......
*/
System.out.print("请输入您的访问路径:");
Scanner s = new Scanner(System.in);
// 用户的请求路径 /bbbb
String key = s.nextLine(); // Tomcat服务器已经获取到了用户的请求路径了。
// Tomcat服务器应该通过用户的请求路径找对应的XXXServlet
// 请求路径和XXXServlet之间的关系应该由谁指定呢?
// 对于Tomcat服务器来说需要解析配置文件
/* ResourceBundle bundle = ResourceBundle.getBundle("web.properties");
String className=bundle.getString(提示key:"key"); */
FileReader reader = new FileReader("web.properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
// 通过key获取value
String className = pro.getProperty(key);
// 通过反射机制创建对象
Class clazz = Class.forName(className);
Object obj = clazz.newInstance(); // obj的类型对于Tomcat服务器开发人员来说不知道。
// 但是Tomcat服务器的开发者知道,你写的XXXXServlet一定实现了Servlet接口
Servlet servlet = (Servlet)obj;
servlet.service();
}
}
注意:
这个配置文件的文件名不能乱来。固定的。
这个配置文件的存放路径不能乱来。固定的。
servlet规范中规定了:
一个合格的webapp应该是一个怎样的目录结构。
一个合格的webapp应该有一个怎样的配置文件。
一个合格的webapp配置文件路径放在哪里。
一个合格的webapp中java程序放在哪里。
这些都是Servlet规范中规定的。
Tomcat服务器要遵循Servlet规范。JavaWEB程序员也要遵循这个Servlet规范。这样Tomcat服务器和webapp才能解耦合。
2.4开发一个带有Servlet(Java小程序)的webapp(重点)
第一步:在webapps下建立文件夹
注意:
1.webapproot()为你的项目名字
2.classes存放的是Java程序编译之后的class文件
3.web.xml内容为
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
metadata-complete="true">
<!--servlet描述信息-->
<!--任何一个servlet都对应一个servlet-mapping -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<!--这个位置必须是带有包名的全限定类名-->
<servlet-class>com.bjpowernode.servlet.HelloServlet</servlet-class>
</servlet>
<!--servlet映射信息-->
<servlet-mapping>
<!--这个也是随便的,不过这里写的内容要和上面的一样。-->
<servlet-name>HelloServlet</servlet-name>
<!--这里需要一个路径-->
<!--这个路径唯一的要求是必须以 / 开始-->
<!--当前这个路径可以随便写-->
<url-pattern>/HelloServlet.index</url-pattern>
</servlet-mapping>
</web-app>
第三步:编写并编译一个java程序(必须实现Servlet接口)
java源代码你愿意在哪里就在哪里,位置无所谓,你只需要将java源代码编译之后的class文件放到classes目录下即可。
package com.bjpowernode.servlet;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.ServletConfig;
import java.io.IOException;
import java.io.PrintWriter;
public class HelloServlet implements Servlet{
// 5个方法
public void init(ServletConfig config) throws ServletException{
}
public void service(ServletRequest request,ServletResponse response)
throws ServletException , IOException{
// 向控制台打印输出
System.out.println("My First Servlet, Hello Servlet");
// 设置响应的内容类型是普通文本或html代码
// 需要在获取流对象之前设置,有效。
response.setContentType("text/html");
// 怎么将一个信息直接输出到浏览器上?
// 需要使用ServletResponse接口:response
// response表示响应:从服务器向浏览器发送数据叫做响应。
PrintWriter out = response.getWriter();
out.print("Hello Servlet, You are my first servlet!");
// 浏览器是能够识别html代码的,那我们是不是应该输出一段HTML代码呢?
out.print("<h1>hello servlet,你好Servlet</h1>");
// 这是一个输出流,负责输出字符串到浏览器
// 这个输出流不需要我们刷新,也不需要我们关闭,这些都由Tomcat来维护。
/*
out.flush();
out.close();
*/
}
public void destroy(){
}
public String getServletInfo(){
return "";
}
public ServletConfig getServletConfig(){
return null;
}
}
将以上编译之后的HelloServlet.class文件拷贝到WEB-INF\classes目录下。
第四步:在浏览器输入网址
启动tomcat服务器: startup.bat
关闭tomcat服务器:stop.bat
2.5使用集成工具IDEA开发一个带有Servlet(java小程序)的web
第一步:基础搭建
1.创建一个新工程
2.创建一个新模块
2.1模块右击---->Add Framework Support…(添加框架支持)------>选择Web Application
(一个符合Servlet规范的webpp目录结构。)
第二步:编写Servlet
1.编写Servlet
1.1这个时候发现Servlet.class文件没有。怎么办?
File --> Project Structrue --> Modules---->Dependeencies—>添加Library或者JAR
2.实现jakarta.servlet.Servlet接口中的5个方法。
3.在Servlet当中的service方法中编写业务代码(我们这里连接数据库了。)
4.在WEB-INF目录下新建了一个子目录:lib 并且将连接数据库的驱动jar包放到lib目录下。
package com.javaweb.servlet;
import jakarta.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.*;
public class StudentServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest Request, ServletResponse Response) throws ServletException, IOException {
//设置响应的内容类型
Response.setContentType("text/html");
PrintWriter out=Response.getWriter();
//连接数据库(JDBC)
Connection conn=null;
PreparedStatement ps=null;
ResultSet res=null;
try {
Class.forName("com.mysql.cj.jdbc.Driver");
String url="jdbc:mysql://localhost:3306/jdbcStudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username="root";
String password="123456";
conn=DriverManager.getConnection(url,username,password);
String sql="select id,name from users";
ps=conn.prepareStatement(sql);
res=ps.executeQuery();
while(res.next()){
int id=res.getInt("id");
String name=res.getString("name");
out.print(id+","+name+"<br>");
System.out.println("11111");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}finally {
if(res!=null){
try {
res.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(ps!=null){
try {
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
第三步:在web.xml文件中完成StudentServlet类的注册
<?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>studentServlet</servlet-name>
<servlet-class>com.javaweb.servlet.StudentServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>studentServlet</servlet-name>
<url-pattern>/servlet/student</url-pattern>
</servlet-mapping>
</web-app>
第四步:给一个html页面,在HTML页面中编写一个超链接
- student.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>student page</title>
</head>
<body>
<!--这里的项目名是 /xmm,无法动态获取,先写死-->
<a href="/xmm/servlet/student">student list</a>
</body>
</html>
第五步:让IDEA工具去关联Tomcat服务器。
1.Add Configuration
2.左上角加号,点击Tomcat Server --> local
3.Deployment(点击这个用来部署webapp),继续点击加号,部署即可。修改 Application context为:/xmm
第六步:启动tom服务器,浏览器输入地址
打开浏览器,在浏览器地址栏上输入:http://localhost:8080/xmm/student.html
注意:前端发送请求要加项目名
三、servlet对象的生命周期
3.1 servlet生命周期
研究:默认情况下,服务器在启动的时候Servlet对象并不会被实例化。
这个设计是合理的。用户没有发送请求之前,如果提前创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet如果一直没有用户访问,显然这个Servlet对象是一个废物,没必要先创建。
3.2 Servlet适配器
GenericServlet
package com.javaweb.servlet;
import jakarta.servlet.*;
import java.io.IOException;
/**
* 编写一个标准通用的Servlet,起名: GenericServlet
* 以后所有的Servlet类都不要直接实现Servlet接口了。
* 以后所有的Servlet类都要继承GenericServlet类。
* GenericServlet就是一个适配器
*/
public abstract class GenericServlet implements Servlet {
//成员变量
private ServletConfig config;
/**
*init方法中的ServletConfig对象是小猫咪创建好的。
* 这个ServletConfig对象目前在init方法的参数上,属于局部变量。
* 那么ServletConfig对象肯定以后要在service方法中使用,怎么才能保iServletConfig对象(在iservice方法中能够使用呢?
*/
@Override
public final void init(ServletConfig config) throws ServletException {
this.config=config;
//调用init()方法
init();
}
/**
* 这个init方法是供子类重写的。
*/
public void init(){
}
@Override
public ServletConfig getServletConfig() {
return config;
}
/**
* 抽象方法,这个方法最常用,所有子类必须实现service方法
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
public abstract void service(ServletRequest servletRequest, ServletResponse servletResponse)
throws ServletException, IOException;
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
package com.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import java.io.IOException;
public class LoginServlet extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("正在登陆中....");
}
}
3.3 ServletConfig
package com.javaweb.servlet;
import jakarta.servlet.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
/**
*ServletConfig
* 1. ServletConfig是什么?
* jakarta.servlet.ServletConfig
* 显然ServletConfig Servlet规范中的一员。
* ServletConfig是一个接口。(jakarta.servlet.Servlet是一个接口)
* 2.谁去实现了这个接口呢?
* public class org.apache.catalina.core.StandardWrapperFacade implements ServletConfig{}
* 结论:Tomcat服务器实现了ServletConfig接口
* 思考:如果把Tomcat服务器换成jetty服务器,输出ServletConfig对象的时候,还是这个结果吗?
* 不一定一样,包名类名可能和Tomcat不一样。但是他们都实现了ServletConfig这个规范。
* 3,一个Servlet对象中有一个ServletConfig对象。(Servlet 和iServletConfig对象是一对一。>
* 100个Servlet,就应该有100个ServletConfig对象。
* 4. ServletConfig对象是谁创建的?在什么时候创建的?
* Tomcat服务器(WEB服务器)创建了ServletConfig对象。
* 在创建Servlet对象的时候,同时创建lServletConfig对象。
* 5. ServletConfig接口到底是干啥的?有什么用呢?
* Config是哪个单词的缩写?
* configuration
* ServletConfig对象被翻译为:Servlet对象的配置信息对象。
* 6. ServletConfig对象中到底包装了什么信息呢?
* <servlet>
* <servlet-name>configTest</servlet-name>
* <servlet-class>com.javaweb.servlet.ConfigTestServlet</servlet-class>
* </servlet>
* ServletConfig对象中包装的信息是:
* web .xml文件中<servlet></servlet>标签的配置信息。
*
* Tomcat小猫咪解析web.xml文件,将web.xml文件中<servlet></servlet>标签中的配置信息自动包装到ServletConfig 对象中 。
* 7. ServletConfig有哪些方法?
* getServletConfig()
* getInitParameterNames()
* getInitParameter(java.lang.string name)
* 第1个方法:
* public String getInitParameter(String name);
* 第2个方法:
* public Enumeration<String> getInitParameterNames();
* 第3个方法:
* public ServletContext getServletContext();
* 第4个方法;
* public String getServletName()
* 以上的4个方法,在自己编写的Servlet类当中也可以使用this 去调用。(这个Servlet继承了GenericServlet)
*/
public class ConfigTestServlet extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out=response.getWriter();
//获取ServletConfig对象
ServletConfig config=this.getServletConfig();
//输出该对象
//org.apache.catalina.core.StandardWrapperFacade@640259a9
out.print("ServletConfig对象: "+config);
out.print("<br>");
//获取<servlet-name></servlet-name>
String servletName = config.getServletName();
out.print("<servlet-name>"+servletName+"</servlet-name>");
out.print("<br>");
//通过ServletConfig对象的两个方法,可以获取到web.xml文件中的初始化参数配置信息。
//java.util.Enumeration<java.lang.string>getInitParameterNames()
//获取所有的初始化参数的name
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()){
String parameterName = initParameterNames.nextElement();
String parameterValue = config.getInitParameter(parameterName);
out.print(parameterName+"="+ parameterValue);
out.print("<br>");
}
//获取所有的初始化参数的值 value
/*//java.lang.String getInitParameter(java.lang.string name)
String driver = config.getInitParameter("driver");
out.print(driver);*/
//实际上获取一个Servlet对象的初始化参数,可以不用获取ServletConfig对象。直接通过this也可以。
Enumeration<String> names = this.getInitParameterNames();
while (names.hasMoreElements()){
String name = names.nextElement();
String value = this.getInitParameter(name);
System.out.println(name + "=" + value);
}
//怎么获取ServletContext对象呢?
//通过ServletConfig对象获取ServletContext对象。
ServletContext application = config.getServletContext();
out.print("<br>"+application);
//第二种方式:通过this也可以获取ServletContext对象。
ServletContext application2 = this.getServletContext();
out.print("<br>"+application2);
}
}
<?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>configTest</servlet-name>
<servlet-class>com.javaweb.servlet.ConfigTestServlet</servlet-class>
<!--这里是可以配置一个Servlet对象的初始化信息的。-->
<init-param>
<param-name>driver</param-name>
<param-value>com.mysql.cj.jdbc.Driver</param-value>
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>cjdbc:mysql://localhost:3306/jdbcStudy</param-value>
</init-param>
<init-param>
<param-name>user</param-name>
<param-value>root</param-value>
</init-param>
<init-param>
<param-name>password</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>configTest</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>configTest2</servlet-name>
<servlet-class>com.javaweb.servlet.ConfigTestServlet2</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>configTest2</servlet-name>
<url-pattern>/test2</url-pattern>
</servlet-mapping>
</web-app>
3.4 ServletContext
缓存机制:
四.Http协议
HTTP协议:是W3C制定的一种超文本传输协议。(通信协议:发送消息的模板提前被制定好。)
HTTP协议包括:
- 请求协议
浏览器 向 WEB服务器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。 - 响应协议
WEB服务器 向 浏览器发送数据的时候,这个发送的数据需要遵循一套标准,这套标准中规定了发送的数据具体格式。
1.HTTP的请求协议(B --> S)
详细参考链接:https://www.yuque.com/csy/ykokl4/uufokl#TaTl9
○ HTTP的请求协议包括:4部分
- 请求行
- 请求头
- 空白行
- 请求体
○ HTTP请求协议的具体报文:GET请求
- 请求行
- 请求头
- 空白行
- 请求体
2.HTTP的响应协议(S --> B)
3.GET和POST有什么区别?
到目前为止,只有一种情况可以发送POST请求:使用form表单,并且form标签中的method属性值为:method=“post”。
五.HttpServlet
● 我们编写的HelloServlet直接继承HttpServlet,直接重写HttpServlet类中的service()方法行吗?
○ 可以,只不过你享受不到405错误。享受不到HTTP协议专属的东西。
● 到今天我们终于得到了最终的一个Servlet类的开发步骤:
○ 第一步:编写一个Servlet类,直接继承HttpServlet
○ 第二步:重写doGet方法或者重写doPost方法,到底重写谁,javaweb程序员说了算。
○ 第三步:将Servlet类配置到web.xml文件当中。
○ 第四步:准备前端的页面(form表单),form表单中指定请求路径即可。
欢迎资源文件
● 动态资源:Servlet类。
○ 步骤:
■ 第一步:写一个Servlet
public class WelcomeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("<h1>welcome come!!</h1>");
}
}
第二步:在web.xml文件中配置servlet
<servlet>
<servlet-name>welcomeServlet</servlet-name>
<servlet-class>com.javaweb.servlet.WelcomeServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcomeServlet</servlet-name>
<url-pattern>/aaa</url-pattern>
</servlet-mapping>
第三步:在web.xml文件中配置欢迎页
<!-- 配置欢迎页-->
<welcome-file-list>
<welcome-file>aaa</welcome-file>
</welcome-file-list>
关于WEB-INF目录
● 在WEB-INF目录下新建了一个文件:welcome.html
● 打开浏览器访问:http://localhost:8080/servlet07/WEB-INF/welcome.html 出现了404错误。
● 注意:放在WEB-INF目录下的资源是受保护的。在浏览器上不能够通过路径直接访问。所以像HTML、CSS、JS、image等静态资源一定要放到WEB-INF目录之外。
六.HttpServletRequest接口详解
● HttpServletRequest是一个接口,全限定名称:jakarta.servlet.http.HttpServletRequest
● HttpServletRequest对象中都有什么信息?都包装了什么信息?
○ HttpServletRequest对象是Tomcat服务器负责创建的。这个对象中封装了什么信息?封装了HTTP的请求协议。
○ 实际上是用户发送请求的时候,遵循了HTTP协议,发送的是HTTP的请求协议,Tomcat服务器将HTTP协议中的信息以及数据全部解析出来,然后Tomcat服务器把这些信息封装到HttpServletRequest对象当中,传给了我们javaweb程序员。
○ javaweb程序员面向HttpServletRequest接口编程,调用方法就可以获取到请求的信息了。
● request和response对象的生命周期?
○ request对象和response对象,一个是请求对象,一个是响应对象。这两个对象只在当前请求中有效。
○ 一次请求对应一个request。
○ 两次请求则对应两个request。
6.1 常用方法
获取用户提交的数据
怎么获取前端浏览器用户提交的数据?
Map<String,String[]> getParameterMap() 这个是获取Map
Enumeration<String> getParameterNames() 这个是获取Map集合中所有的key
String[] getParameterValues(String name) 根据key获取Map集合的value
String getParameter(String name) 获取value这个一维数组当中的第一个元素。这个方法最常用。
// 以上的4个方法,和获取用户提交的数据有关系。
Map<String,String>
key存储String
value存储String
这种想法对吗?不对。
如果采用以上的数据结构存储会发现key重复的时候value覆盖。
key value
---------------------
username abc
userpwd 111
aihao s
aihao d
aihao tt
这样是不行的,因为map的key不能重复。
Map<String, String[]>
key存储String
value存储String[]
key value
-------------------------------
username {"abc"}
userpwd {"111"}
aihao {"s","d","tt"}
注意:前端表单提交数据的时候,假设提交了120这样的“数字”,其实是以字符串"120"的方式提交的,所以服务器端获取到的一定是一个字符串的"120",而不是一个数字。(前端永远提交的是字符串,后端获取的也永远是字符串。)
四个方法的使用
package com.javaweb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class RequestTestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print(request);
out.print("<br>");
out.print("RequestTestServlet test....");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/*4.获取参数Map集合*/
Map<String, String[]> parameterMap = request.getParameterMap();
// 遍历Map集合(获取Map集合中所有的key,遍历)
Set<String> keys = parameterMap.keySet();
Iterator<String> it = keys.iterator();
while (it.hasNext()){
String key = it.next();
System.out.print(key+"=");
String[] values = parameterMap.get(key);
for (String value:values) {
System.out.print(value+",");
}
System.out.println();
}
/*3.直接通过getParameterNames()这个方法,可以直接获取这个Map集合的所有key*/
Enumeration<String> names = request.getParameterNames();
while(names.hasMoreElements()){
String name = names.nextElement();
System.out.println(name);
}
/*2.既然是checkbox,调用方法:request.getParameterValues("interest")*/
String[] usernames = request.getParameterValues("username");
String[] userpwds = request.getParameterValues("userpwd");
String[] aihaos = request.getParameterValues("aihao");
for (String username:usernames) {
System.out.println(username);
}
for (String userpwd:userpwds) {
System.out.println(userpwd);
}
for (String aihao:aihaos) {
System.out.println(aihao);
}
/*1.最常用的方式
通过name获取value这个一维数组的第一个元素
String getParameter(String name)*/
String username = request.getParameter("username");
String userpwd = request.getParameter("userpwd");
System.out.println(username);
System.out.println(userpwd);
}
}
请求域对象request
请求域”对象要比“应用域”对象范围小很多。生命周期短很多。请求域只在一次请求内有效。
一个请求对象request对应一个请求域对象。一次请求结束之后,这个请求域就销毁了。
请求域对象也有这三个方法:
// 存(怎么向request请求域中存数据)
public void setAttribute(String name, Object value); // map.put(k, v)
// 取(怎么从request请求域中取数据)
public Object getAttribute(String name); // Object v = map.get(k)
// 删(怎么删除request请求域中的数据)
public void removeAttribute(String name); // map.remove(k)
● 请求域和应用域的选用原则?
尽量使用小的域对象,因为小的域对象占用的资源较少。
两个Servlet怎么共享数据?
● 将数据放到ServletContext应用域当中,当然是可以的,但是应用域范围太大,占用资源太多。不建议使用。
● 可以将数据放到request域当中,然后AServlet转发到BServlet,保证AServlet和BServlet在同一次请求当中,这样就可以做到两个Servlet,或者多个Servlet共享同一份数据。
请求转发
1.原理: 是由WEB服务器来控制的。A资源跳转到B资源,这个跳转动作是Tomcat服务器内部完成的。
// 第一步:获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
// 第二步:调用转发器的forward方法完成跳转/转发
dispatcher.forward(request,response);
// 第一步和第二步代码可以联合在一起。
request.getRequestDispatcher("/b").forward(request,response);
//注意:转发的时候是一次请求,会将当前的request和response对象传递给下一个servlet.
● 转发的下一个资源必须是一个Servlet吗?
- 不一定,只要是Tomcat服务器当中的合法资源,都是可以转发的。例如:html…
- 注意:转发的时候,路径的写法要注意,转发的路径以“/”开始,不加项目名
关于request对象中两个非常容易混淆的方法:
// uri?username=zhangsan&userpwd=123&sex=1
String username = request.getParameter("username");
// 之前一定是执行过:request.setAttribute("name", new Object())
Object obj = request.getAttribute("name");
// 以上两个方法的区别是什么?
// 第一个方法:获取的是用户在浏览器上提交的数据。
// 第二个方法:获取的是请求域当中绑定的数据。
HttpServletRequest接口的其他常用方法:
// 获取客户端的IP地址
String remoteAddr = request.getRemoteAddr();
// get请求在请求行上提交数据。
// post请求在请求体中提交数据。
// 设置请求体的字符集。(显然这个方法是处理POST请求的乱码问题。这种方式并不能解决get请求的乱码问题。)
// Tomcat10之后,request请求体当中的字符集默认就是UTF-8,不需要设置字符集,不会出现乱码问题。
// Tomcat9前(包括9在内),如果前端请求体提交的是中文,后端获取之后出现乱码,怎么解决这个乱码?执行以下代码。
request.setCharacterEncoding("UTF-8");
// 在Tomcat9之前(包括9),响应中文也是有乱码的,怎么解决这个响应的乱码?
response.setContentType("text/html;charset=UTF-8");
// 在Tomcat10之后,包括10在内,响应中文的时候就不在出现乱码问题了。以上代码就不需要设置UTF-8了。
// 注意一个细节
// 在Tomcat10包括10在内之后的版本,中文将不再出现乱码。(这也体现了中文地位的提升。)
// get请求乱码问题怎么解决?
// get请求发送的时候,数据是在请求行上提交的,不是在请求体当中提交的。
// get请求乱码怎么解决
// 方案:修改CATALINA_HOME/conf/server.xml配置文件
<Connector URIEncoding="UTF-8" />
// 注意:从Tomcat8之后,URIEncoding的默认值就是UTF-8,所以GET请求也没有乱码问题了。
// 获取应用的根路径
String contextPath = request.getContextPath();
// 获取请求方式
String method = request.getMethod();
// 获取请求的URI
String uri = request.getRequestURI(); // /aaa/testRequest
// 获取servlet path
String servletPath = request.getServletPath(); // /testRequest
在一个web应用中如何完成资源的跳转
在一个web应用中通过两种方式,可以完成资源的跳转:
- 第一种方式:转发
- 第二种方式:重定向
转发:
转发:
重定向:
转发和重定向区别:
转发和重定向应该如何选择?什么时候使用转发,什么时候使用重定向?
● 如果在上一个Servlet当中向request域当中绑定了数据,希望从下一个Servlet当中把request域里面的数据取出来,使用转发机制。
● 剩下所有的请求均使用重定向。(重定向使用较多。)
● 他俩跳转的资源只要是服务器内部合法的资源即可。(Servlet,JSP,HTML)…
● 转发会存在浏览器刷新问题
Servlet注解
package com.javawvb.servlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebInitParam;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
@WebServlet(name="hello",
urlPatterns = {"/hello1","/hello2","/hello3"},
//loadOnStartup = 1,
initParams = {@WebInitParam(name ="username",value = "root"),@WebInitParam(name = "password",value = "123")})
public class HelloServlet extends HttpServlet {
public HelloServlet() {
System.out.println("无参数构造方法执行");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
//获取Servlet Name
String servletName = getServletName();
out.print("servlet name= "+servletName+"<br>");
//获取Servlet Name
String contextPath = request.getContextPath();
out.print("servlet path= "+contextPath+"<br>");
//获取初始化参数
Enumeration<String> names = getInitParameterNames();
while (names.hasMoreElements()){
String name = names.nextElement();
String value = getInitParameter(name);
out.print(name+"="+value+"<br>");
}
}
}
// @WebServlet(urlPatterns = { " /welcome1","/welcome2"3)
// 注意:当注解的属性是一个数组,并且数组中只有一个元素,大括号可以省略。
// @WebServlet(urlPatterns = "/welcome ")
//这个value属性和urlPatterns属性一致,都是用来指定Servlet的映射路径的。
// @WebServlet(value = {" /welcome1","/welcome2"})
//如果注解的属性名是value的话,属性名也是可以省略的。
//@WebServlet(value = " /welcome1")
@WebServlet("/welcome")
public class WelcomeServlet extends HttpServlet {}
七.JSP
7.1 概念
7.2 JSP的语法
1.在jsp文件中直接编写文字会被翻译到servlet类的service方法的out.write(“翻译到这里”),直接翻译到双引号里,被java程序当做普通字符串打印输出到浏览器。
(在JSP中编写的HTML CSS JS代码,这些代码对于JSP来说只是一个普通的字符串。但是JSP把这个普通的字符串一旦输出到浏览器,浏览器就会对HTML CSS JS进行解释执行。展现一个效果.)
2.在JSP中编写java程序
<% java语句; %>
//向浏览器上输出一个java变量。
<% String name = “jack”;
out.write("name = " + name); %>
● 在这个符号当中编写的被视为java程序,被翻译到Servlet类的service方法内部。
● 在service方法当中编写的代码是有顺序的,方法体当中的代码要遵循自上而下的顺序依次逐行执行。
● service方法当中不能写静态代码块,不能写方法,不能定义成员变量。。。。。。
● 在同一个JSP当中 <%%> 这个符号可以出现多个。
● 注意:以上代码中的out是JSP的** **。可以直接拿来用。当然,必须只能在service方法内部使用。
<%! %> 在这个符号当中编写的java程序会自动翻译到service方法之外
<%--在这个符号当中编写的java程序会自动翻译到service方法之外。--%>
<%!
//成员变量
private String name="jackson";
//静态代码块
static {
System.out.println("静态代码块执行!");
}
//方法
public static void m1(){
System.out.println("m1 method execute!");
}
%>
这个语法很少用,为什么?不建议使用,因为在service方法外面写静态变量和实例变量,都会存在线程安全问题,ISP就是servlet,servlet是单例的,多线程并发的环境下,这个静态变量和实例变量一旦有修改操作,必然会存在全问题。
<%= %> 这个符号会被翻译到哪里?最终翻译成什么?
● 翻译成了这个java代码: out.print();
翻译到service方法当中了。
什么时候使用<%=%>输出呢?输出的内容中含有java的变量,输出的内容是一个动态的内容,不是一个死的字符串。如果输出的是一个固定的字符串,直接在JSP文件中编写即可。
3.在JSP中如何编写JSP的专业注释
<!--这种注释属于HTML的注释,这个注释信息仍然会被翻译到java源代码当中,不建议。-->
<%--JSP的专业注释,不会被翻译到java源代码当中。--%>
<%--注释
int i;
--%>
JSP基础语法总结:
7.3 session和cookie
关于B/S结构系统的session机制
● 什么是会话?
○ 用户打开浏览器,进行一系列操作,然后最终将浏览器关闭,这个整个过程叫做:一次会话。会话在服务器端也有一个对应的java对象,这个java对象叫做:session。
○ 什么是一次请求:用户在浏览器上点击了一下,然后到页面停下来,可以粗略认为是一次请求。请求对应的服务器端的java对象是:request。
○ 一个会话当中包含多次请求。(一次会话对应N次请求。)
● 在java的servlet规范当中,session对应的类名:HttpSession(jarkata.servlet.http.HttpSession)
● session机制属于B/S结构的一部分。如果使用php语言开发WEB项目,同样也是有session这种机制的。session机制实际上是一个规范。然后不同的语言对这种会话机制都有实现。
● session对象最主要的作用是:保存会话状态。(用户登录成功了,这是一种登录成功的状态,你怎么把登录成功的状态一直保存下来呢?使用session对象可以保留会话状态。)
● 为什么需要session对象来保存会话状态呢?
○ 因为HTTP协议是一种无状态协议。
○ 什么是无状态:请求的时候,B和S是连接的,但是请求结束之后,连接就断了。为什么要这么做?HTTP协议为什么要设计成这样?因为这样的无状态协议,可以降低服务器的压力。请求的瞬间是连接的,请求结束之后,连接断开,这样服务器压力小。
○ 只要B和S断开了,那么关闭浏览器这个动作,服务器知道吗?
■ 不知道。服务器是不知道浏览器关闭的。
● 为什么不使用request对象保存会话状态?为什么不使用ServletContext对象保存会话状态?
○ request.setAttribute()存,request.getAttribute()取,ServletContext也有这个方法。request是请求域。ServletContext是应用域。
○ request是一次请求一个对象。
○ ServletContext对象是服务器启动的时候创建,服务器关闭的时候销毁,这个ServletContext对象只有一个。
○ ServletContext对象的域太大。
○ request请求域(HttpServletRequest)、session会话域(HttpSession)、application域(ServletContext)
○ request < session < application
session的实现原理:
● JSESSIONID=xxxxxx 这个是以Cookie的形式保存在浏览器的内存中的。浏览器只要关闭。这个cookie就没有了。
● session列表是一个Map,map的key是sessionid,map的value是session对象。
● 用户第一次请求,服务器生成session对象,同时生成id,将id发送给浏览器。
● 用户第二次请求,自动将浏览器内存中的id发送给服务器,服务器根据id查找session对象。
● 关闭浏览器,内存消失,cookie消失,sessionid消失,会话等同于结束
● Cookie禁用了,session还能找到吗?
○ cookie禁用是什么意思?服务器正常发送cookie给浏览器,但是浏览器不要了。拒收了。并不是服务器不发了。
○ 找不到了。每一次请求都会获取到新的session对象。
○ cookie禁用了,session机制还能实现吗?
■ 可以。需要使用URL重写机制。
■http://localhost:8080/servlet12/test/session;jsessionid=19D1C99560DCBF84839FA43D58F56E16
■ URL重写机制会提高开发者的成本。开发人员在编写任何请求路径的时候,后面都要添加一个sessionid,给开发带来了很大的难度,很大的成本。所以大部分的网站都是这样设计的:你要是禁用cookie,你就别用了。
销毁session对象:session.invalidate();
Cookie
session的实现原理中,每一个session对象都会关联一个sessionid,例如:
- JSESSIONID=41C481F0224664BDB28E95081D23D5B8
- 以上的这个键值对数据其实就是cookie对象。
- 对于session关联的cookie来说,这个cookie是被保存在浏览器的“运行内存”当中。
- 只要浏览器不关闭,用户再次发送请求的时候,会自动将运行内存中的cookie发送给服务器。
- 例如JSESSIONID=41C481F0224664BDB28E95081D23D5B8就会再次发送给服务器。
- 服务器就是根据41C481F0224664BDB28E95081D23D5B8这个值来找到对应的session对象的
● cookie机制和session机制其实都不属于java中的机制,实际上cookie机制和session机制都是HTTP协议的一部分。php开发中也有cookie和session机制,只要是你是做web开发,不管是什么编程语言,cookie和session机制都是需要的。
● HTTP协议中规定:任何一个cookie都是由name和value组成的。name和value都是字符串类型的。
● 在java的servlet中,对cookie提供了哪些支持呢?
○ 提供了一个Cookie类来专门表示cookie数据。jakarta.servlet.http.Cookie;
○ java程序怎么把cookie数据发送给浏览器呢?response.addCookie(cookie);
● 在HTTP协议中是这样规定的:当浏览器发送请求的时候,会自动携带该path下的cookie数据给服务器。(URL。)
@WebServlet("/cookie/generate")
public class GenerateCookie extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//创建Cookie对象
Cookie cookie = new Cookie("productid","123");
Cookie cookie1 = new Cookie("username", "zhangsan");
//设置cookie在一小时之后失效。(保存在硬盘文件中)
//cookie.setMaxAge(60*60);
//设置cookie的有效期为0,表示该cookie被删除。主要应用在:使用这种方式删除浏/览器上的同名cookie。
//cookie.setMaxAge(0);
//设置cookie的有效期<0,表示该cookie不会被存储。(表示不会被存储到硬盘文件中。会放在浏览器运行内存当中。)
cookie.setMaxAge(-1); //和不调用sexMaxAge是同一个效果。
cookie1.setMaxAge(-1);
//默认情况下,没有设置path的时候,cookie关联的路径是什么?
//手动设置路径
cookie.setPath("/Servlet11");
cookie1.setPath(request.getContextPath());
//将cookie响应到浏览器
response.addCookie(cookie);
response.addCookie(cookie1);
}
}
浏览器发送cookie给服务器了,服务器中的java程序怎么接收?
Cookie[] cookies = request.getCookies(); // 这个方法可能返回null
if(cookies != null){
for(Cookie cookie : cookies){
// 获取cookie的name
String name = cookie.getName();
// 获取cookie的value
String value = cookie.getValue();
}
}
7.4 JSP指令
JSP的指令
● 指令的作用:指导JSP的翻译引擎如何工作(指导当前的JSP翻译引擎如何翻译JSP文件。)
● 指令包括哪些呢?
○ include指令:包含指令,在JSP中完成静态包含,很少用了。(这里不讲)
○ taglib指令:引入标签库的指令。这个到JJSTL标签库的时候再学习。现在先不管。
○ page指令:目前重点学习一个page指令。
● 指令的使用语法是什么?
○ <%@指令名 属性名=属性值 属性名=属性值 属性名=属性值…%>
● 关于page指令当中都有哪些常用的属性呢?
<%@page session="true|false" %>
true表示启用JSP的内置对象session,表示一定启动session对象。没有session对象会创建。
如果没有设置,默认值就是session="true"
session="false" 表示不启用内置对象session。当前JSP页面中无法使用内置对象session。
<%@page contentType="text/json" %>
contentType属性用来设置响应的内容类型
但同时也可以设置字符集。
<%@page contentType="text/json;charset=UTF-8" %>
<%@page import="java.util.List, java.util.Date, java.util.ArrayList" %>
<%@page import="java.util.*" %>
import语句,导包。
<%@page errorPage="/error.jsp" %>
当前页面出现异常之后,跳转到error.jsp页面。
errorPage属性用来指定出错之后的跳转位置。
<%@page isErrorPage="true" %>
表示启用JSP九大内置对象之一:exception
默认值是false。
7.5 JSP的九大内置对象
○ jakarta.servlet.jsp.PageContext pageContext 页面作用域
○ jakarta.servlet.http.HttpServletRequest request 请求作用域
○ jakarta.servlet.http.HttpSession session 会话作用域
○ jakarta.servlet.ServletContext application 应用作用域
■ pageContext < request < session < application
■ 以上四个作用域都有:setAttribute、getAttribute、removeAttribute方法。
■ 以上作用域的使用原则:尽可能使用小的域。
○ java.lang.Throwable exception
○ jakarta.servlet.ServletConfig config
○ java.lang.Object page (其实是this,当前的servlet对象)
○ jakarta.servlet.jsp.JspWriter out (负责输出)
○ jakarta.servlet.http.HttpServletResponse response (负责响应)
7.6 EL表达式
1.什么是EL表达式
2.EL表达式的使用
<%
// 创建User对象
User user = new User();
user.setUsername("jackson");
user.setPassword("1234");
user.setAge(50);
// 将User对象存储到某个域当中。一定要存,因为EL表达式只能从某个范围中取数据。
// 数据是必须存储到四大范围之一的。
request.setAttribute("userObj", user);
%>
<%--使用EL表达式取--%>
${这个位置写什么????这里写的一定是存储到域对象当中时的name}
要这样写:
${userObj}
等同于java代码:<%=request.getAttribute("userObj")%>
你不要这样写:${"userObj"}
面试题:
${abc} 和 ${"abc"}的区别是什么?
${abc}表示从某个域中取出数据,并且被取的这个数据的name是"abc",之前一定有这样的代码: 域.setAttribute("abc", 对象);
${"abc"} 表示直接将"abc"当做普通字符串输出到浏览器。不会从某个域中取数据了。
${userObj} 底层是怎么做的?从域中取数据,取出user对象,然后调用user对象的toString方法,转换成字符串,输出到浏览器。
<%--如果想输出对象的属性值,怎么办?--%>
${userObj.username} 使用这个语法的前提是:User对象有getUsername()方法。
${userObj.password} 使用这个语法的前提是:User对象有getPassword()方法。
${userObj.age} 使用这个语法的前提是:User对象有getAge()方法。
${userObj.email} 使用这个语法的前提是:User对象有getEmail()方法。
EL表达式中的. 这个语法,实际上调用了底层的getXxx()方法。
注意:如果没有对应的get方法,则出现异常。报500错误。
${userObj.addr222.zipcode}
以上EL表达式对应的java代码:
user.getAddr222().getZipcode()
<%@ page import="jakarta.servlet.http.HttpServlet" %>
<%@ page import="jakarta.servlet.http.HttpServletRequest" %>
<%@ page contentType="text/html;charset=UTF-8" isELIgnored="false" %>
<%
request.setAttribute("username","zhangsan");
%>
\${username}
${username}<br>
${username}<br>
<%--
//JSP有九大内置对象
// pageContext, request,session, application, nesponse, out, config, page , exception
//其中四个域对象,其中最小的域是pageContext
// pageContext翻译为:页面上下文。通过pageContext可以获取????--%>
<%--从以下代码来看,pageContext. getRequest()方法是没用的。这是获取request对象。
而JSP中自带了内置对象request,直接用nequest内置对像就行了。--%>
<%=pageContext.getRequest()%><br>
<%=request%><br>
<%--
在EL表达式当中没有request这个隐式对象。
requestScope 这个只代表“请求范围"。不等同于request对象。在EL表达式当中有一个隐式的对象:pageContext
EL表达式中的pageContext和JSP中的九大内置对象pageContext是同一个对象。
--%>
<hr>
<%=((HttpServletRequest)pageContext.getRequest()).getContextPath()%><br>
通过EL表达式获取应用的根:
${pageContext.request.contextPath}<br>
${pageContext.request}<br>
<%=request.getContextPath()%>
3.EL表达式中内置对象
1. pageContext
应用的根路径:${pageContext.request.contextPath}
(因为只有pageContext,没有request内置对象所以通过pageContext的方法获取request)
2. param
用户名:<%=request.getParameter("username")%>
//使用param
用户名:${param.username}
3. paramValues
爱好:${paramValues.aihao[0]}、${paramValues.aihao[1]}、${paramValues.aihao[2]}
4. initParam
<!--Servlet上下文初始化参数-->
<!--上下文初始化参数被封装到:ServletContext对象当中了-->
<context-param>
<param-name>pageSize</param-name>
<param-value>20</param-value>
</context-param>
<%
String a =application.getInitParameter("pageSize");
%>
每页显示的记录条数:<%=a%> //20
//使用initParam
每页显示的记录条数${initParam.pageSize} //20
4.EL表达式中的运算符
7.7. JSTL标签库
1.什么是jstl标签库
● Java Standard Tag Lib (Java标准的标签库)
● JSTL标签库通常结合EL表达式一起使用。目的是让JSP中的java代码消失。
● 标签是写在JSP当中的,但实际上最终还是要执行对应的java程序。(java程序在jar包当中。)
2.使用jstl的步骤
表面使用的是标签,底层实际上还是java程序。
JSTL标签原理:
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
以上uri后面的路径实际上指向了一个×x×.tld文件。
tld文件实际上是一个xml配置文件。
在tld文件中描述了"标签"和"java类"之间的关系。
以上核心标签库对应的tld文件是:c.tld文件。它在哪里。
在jakarta.serv1et.jsp.jst1-2.0.0.jar里面META-INF目录下,有一个c.t1d文件。
配置文件:tld解析
<tag>
<description>对标签的描述</description>
<name>标签的名字</name>
<tag-class>标签对应java类</tag-class>
<body-content>JSP</body-content>标签体当中可以出现的内容,如果是JSp,
就表示标签体中可以出现符合JSp所有语法的代码。例如EL表达式。
<attribute>
<description>
对这个属性的描述
</description>
<name>var</name>属性名
<required>false</required>false表示该属性不是必须的
<rtexprvalue>false</rtexprvalue>false 不支持EL表达式
</attribute>
</tag>
3.常用的标签
<%@ page import="java.util.List" %>
<%@ page import="com.javaweb.jsp.bean.User" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入标签库,jstl核心标签库--%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
<%
List<User> userList=new ArrayList<>();
User u1=new User("110","警车",1);
User u2=new User("120","救护车",2);
User u3=new User("119","消防车",3);
userList.add(u1);
userList.add(u2);
userList.add(u3);
request.setAttribute("userList",userList);
%>
<%
List<User> users=(List<User>) request.getAttribute("userList");
for (User user : users) {
%>
id:<%=user.getUsername()%>,psw:<%=user.getPassword()%>,age:<%=user.getAge()%><br>
<%
}
%>
<hr>
<%--使用core标签库中forEach标签。对List集合进行遍历--%>
<%--EL表达式只能从域中取数据--%>
<%--var后面的名字是随意的。var属性代表的是集合中的每一个元素。--%>
<c:forEach items="${userList}" var="s">
id:${s.username},psw:${s.password},age:${s.age}<br>
</c:forEach>
<%--核心标签库中的if标签--%>
<%--test属性是必须的。test属性支持EL表达式。test属性值只能是boolean类型。--%>
<c:if test="${empty param.username}">
<h1>用户名不能为空</h1>
</c:if>
<%--没有else标签的话,可以搞两个if出来。--%>
<%--if标签还有var属性,不是必须的。--%>
<%--if标签还有scope属性,用来指定van的存储域。也不是必须的。--%>
<%--scope有四个值可选,page(pageContext域)、request(requestil域)、session(session域)、application(application城)--%>
<%--将var中的v存储到request域。--%>
<c:if test="${not empty param.username}" var="v" scope="request">
<h1>欢迎你${param.username}</h1>
</c:if>
<%--v变量中存储的是test届性的值。--%>
${v} <%--true--%>
<hr>
<%--var用来指定循环中的变量--%>
<%--begin开始--%>
<%--end结束--%>
<%--step步长--%>
<%--底层实际上:会将i存储到pageContext域当中。--%>
<c:forEach var="i" begin="1" end="10" step="1">
<%--所以这里才会使用EL表达式将其取出,一定是从某个域当中取出的。--%>
${i}<br>
</c:forEach>
<hr>
<%--var="s"这个s代表的是集合中的每个Student对象--%>
<%--varStatus="这个属性表示var的状态对象,这里是一个java对象,这个java对象代表了var的状态"--%>
<%--varStatus="这个名字是随意的"--%>
<%--varStatus这个状态对象有count属性。可以直接使用。--%>
<c:forEach items="${userList}" var="s" varStatus="userStatus">
<%--varStatus的count值从1开始,以1递增,主要是用于编号/序号。--%>
编号:${userStatus.count} id:${s.username},psw:${s.password},age:${s.age}<br>
</c:forEach>
<hr>
<%--注意:这个嵌套结构不能随便改,只能这样嵌套。类似于if else--%>
<c:choose>
<c:when test="${param.age<18}">
青少年
</c:when>
<c:when test="${param.age<18}">
中年
</c:when>
<c:when test="${param.age<18}">
老年
</c:when>
<c:otherwise>
其他
</c:otherwise>
</c:choose>
7.8 过滤器和监听器
Filter过滤器
Listener监听器
八、MVC三层架构