servlet(server applet):服务器端的Java小程序
web服务器软件都有哪些呢
应用服务器与web服务器的关系
tomcat下载
关于tomcat服务器的目录
关于tomcat的环境配置的问题
访问tomcat服务器的步骤
然后可以在webapps目录下面放一些静态资源文件,这样别人就可以通过浏览器访问这些静态资源
在浏览器上直接输入一个url,然后回车就相当于点击一个超链接
<a href="/oa/login.html">user logina>
<a herf="/oa/test/debug/a.html">a pagea>
在开发一个web程序的过程中涉及到了四个对象,并且每两个对象之间遵循了一定的协议
##### Servlet规范是一个什么规范?
<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_3_1.xsd"
version="3.1"
metadata-complete="true">
web-app>
<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_3_1.xsd"
version="3.1"
metadata-complete="true">
<servlet>
<servlet-name>HelloServletservlet-name>
<servlet-class>src.HelloServletservlet-class>
servlet>
<servlet-mapping>
<servlet-name>HelloServletservlet-name>
<url-pattern>/hellourl-pattern>
servlet-mapping>
web-app>
第十步:启动tomcat服务器
第十一步:打开浏览器,在浏览器地址栏中输入一个url,这个URL必须是
在web.xml中url-pattern
非常重要的一件事情就是浏览器上的请求路径不能随便写,这个请求路径必须和web.xml文件中的url-pattern一致
注意:在浏览器上的请求路径和web.xml中的url-pattern唯一的区别就是:浏览器上的请求路径必须带上项目名称:/crm
浏览器上编写的路径太复杂,可以使用超链接(非常重要:html页面只能放在WEB-INF目录外面)
以后不用编写main方法了,tomcat负责调用main方法,tomcat服务器启动的时候执行的就是main方法,我们Javaweb程序员只需要编写servlet接口的实现类,然后将其注册到web.xml文件中即可
webapproot
-----WEB-INF
-----classes
-----lib
-----web.xml
-----html
-----css
-----js
....
浏览器发送请求,到最终服务器调用servlet中的方法,是怎样的一个过程?
将conf下的logging.properties中配置改成如下:
java.util.logging.ConsoleHandler.encoding = GBK
public void service(ServletRequest request,ServletResponse response) throws ServletException,IOException{
System.out.println("Test Servlet");
//设置响应流的格式
response.setContentType("text/html");//这样就可以向网页中响应文本内容或者html代码了,但是需要注意的是这个方法需要在获取流之前调用
//通过PrintWriter向浏览器中响应信息给用户
PrintWriter out = response.getWriter();
out.print("Welcome to Servlet!!!");
out.print("Test
");
}
package src;
import javax.servlet.Servlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
public class PlayerServlet implements Servlet{
//重写五个方法
public void init(ServletConfig config) throws ServletException{
}
public void service(ServletRequest request,ServletResponse response) throws ServletException,IOException{
//设置文本流格式
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//核心代码
//连接数据库
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try{
//注册驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//获取连接信息
String url = "jdbc:mysql://localhost:3306/mybatis";
String username = "root";
String password = "123456";
conn = DriverManager.getConnection(url,username,password);
//获取预编译的数据库对象
String sql = "select number,name, team,position,salary from player";
ps = conn.prepareStatement(sql);
//执行sql语句
rs = ps.executeQuery();
//处理查询结果集
while(rs.next()){
int number = rs.getInt("number");
String name = rs.getString("name");
String team = rs.getString("team");
String position = rs.getString("position");
double salary = rs.getDouble("salary");
//向用户界面输出查询结果
out.print(number+","+name+","+team+","+position+","+salary+"
");
}
}catch(Exception e){
e.printStackTrace();
}finally{
//释放资源
if(rs != null){
try{
rs.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(ps != null){
try{
ps.close();
}catch(Exception e){
e.printStackTrace();
}
}
if(conn != null){
try{
conn.close();
}catch(Exception e){
e.printStackTrace();
}
}
}
}
public void destroy(){
}
public String getServletInfo(){
return "";
}
public ServletConfig getServletConfig(){
return null;
}
}
<servlet>
<servlet-name>Studentservlet-name>
<servlet-class>com.lkw.servlet01.StudentServletservlet-class>
servlet>
<servlet>
<servlet-name>Studentservlet-name>
<servlet-class>com.lkw.servlet01.StudentServletservlet-class>
<init-param>
<param-name>driverparam-name>
<param-value>com.mysql.cj.jdbc.Driverparam-value>
init-param>
<init-param>
<param-name>urlparam-name>
<param-value>jdbc:mysql://localhost:3306:mybatisparam-value>
init-param>
<init-param>
<param-name>usernameparam-name>
<param-value>rootparam-value>
init-param>
<init-param>
<param-name>passwordparam-name>
<param-value>123456param-value>
init-param>
servlet>
public class TestServletConfig 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();
//获取初始化参数的所有name
Enumeration<String> initParameterNames = config.getInitParameterNames();
//遍历集合
while(initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();//获取name值
//通过name获取name对应的值
String parameter = config.getInitParameter(name);
//向页面中响应获取到的key和value
out.print(name+"="+parameter);
out.print("
");
}
}
}
ServletConfig接口中有四个方法
### ServletContext
public String getInitParameter(String name);//通过初始化参数的name获取value
public Enumeration<String> getInitParameterNames();//获取所有初始化参数的name
<context-param>
<param-name>context pageparam-name>
<param-value>10param-value>
context-param>
<context-param>
<param-name>context indexparam-name>
<param-value>100param-value>
context-param>
//获取应用的根路径(非常重要)因为在java源代码中有一些地方可能会应用到应用的根路径,这个方法可以获取动态获取应用的根路径
public String getContextPath();
//获取某个文件的绝对路径,方法的参数中传递一个文件名,但是要注意的地方是文件名要带上文件夹的名称,如果该文件在webapp的根目录下的话就不用带上文件夹名,但是该文件在根目录下的一个目录下的话,需要带上前面的目录名称
public String getRealPath(String name);
public class TestServletContext extends GenericServlet {
@Override
public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
//获取ServletContext对象
//有两种方式可以获取该对象
//第一种:通过ServletConfig对象来获取
//ServletContext application = this.getServletConfig().getServletContext();
//第二种:通过this直接获取
ServletContext application = this.getServletContext();
//获取初始化参数参数的所有name
Enumeration<String> initParameterNames = application.getInitParameterNames();
//遍历集合
while(initParameterNames.hasMoreElements()){
String name = initParameterNames.nextElement();
String value = application.getInitParameter(name);
//向页面中响应获取到的初始化参数
out.print(name+"="+value+"
");
}
//获取该webapp的根路径
String contextPath = application.getContextPath();
out.print(contextPath+"
");
//获取某个应用的绝对路径,这个应用此时正在项目的根路径下,注意在写路径的时候最好是在最前面加上一个”/“
String path1 = application.getRealPath("/index1.html");
out.print("这个应用此时正在项目的根路径下:"+path1+"
");
//获取某个应用,该应用在一个根目录下的另一个文件夹下
String path2 = application.getRealPath("/realpath/index.html");
out.print("该应用在一个根目录下的另一个文件夹下:"+path2+"
");
}
}
//通过ServletContext对象也是可以记录日志的
public void log(String name);
public void log(String name,Throable t);
//这些日志记录到哪里了?
//我们要知道的一件事情是如果使用的是idea工具启动tomcat服务器的话,那么这个tomcat只是我们在电
//脑上下载的tomcat的副本,算不上真正的tomcat,所以它的日志文件肯定是保存在tomcat副本保存的文
//件夹下面
ServletContext对象还有另一个名字:应用域(后面还有其他域,请求域,会话域)
如果所有用户共享一份数据,并且这个数据很少被修改,并且这个数据量很少,可以将这些数据放到ServletContext这个应用域当中
为什么是所有用户共享的数据?不是共享的没有意义,因为一个webapp只有一个ServletContext对象,只有将数据放进去才有意义
为什么数据量要小?因为数据量比较大的话,太占用内存,并且这个对象的生命周期比较长,从服务器启动直到服务器关闭
为什么这些共享数据很少被修改,或者说几乎不修改?所有共享数据如果涉及到修改操作必然会涉及到线程并发带来的安全问题,所以在ServletContext对象中共享的数据一般都是只读的
数据量小,被所有用户共享,又不修改,这样的数据放到ServletContext对象中,会大大提升效率,因为应用域相当于一个缓存,放到缓存中的数据,下次在使用的时候,不需要从数据库中再次获取,会大大提升效率
//向ServletContext应用域中存放数据
public void setAttribute(String name,Object value);
//向ServletContext应用域中获取数据
public Object getAttribute(String name);
//删除ServletContext应用域中存放的数据
public void removeAttribute(String name);
注意:以后我们在编写Servlet类的时候,实际上是不会直接去继承GenericServlet类的,而因为我们使用的是B/S架构,这种架构是基于HTTP超文本传输协议的,在Servlet规范当中,提供了一个叫做HttpServlet的类,这个类是专门为HTTP协议准备的一个Servlet类
继承链
Servlet(接口)
----GenericServlet(抽象类)
----HttpServlet(抽象类)
GET /servlet05/getServlet?username=lkw&userpwd=123 HTTP/1.1 请求行
Host: 127.0.0.1:8080 请求头
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
空白行
请求体
POST请求的具体报文
POST /servlet05/postServlet HTTP/1.1 请求行
Host: 127.0.0.1:8080 请求头
Connection: keep-alive
Content-Length: 24
Cache-Control: max-age=0
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98", "Google Chrome";v="98"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
Origin: http://127.0.0.1:8080
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Referer: http://127.0.0.1:8080/servlet05/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
空白行
username=lkw&userpwd=123 请求体
HTTP的响应协议
HTTP/1.1 200 ok 状态行
Content-Type: text/html;charset=ISO-8859-1 响应头
Content-Length: 122
Date: Tue, 01 Mar 2022 15:48:19 GMT
Keep-Alive: timeout=20
Connection: keep-alive
空白行
响应体
post
post Page
GET和POST的区别
get请求发送数据的时候,数据会挂在URI后面,并且在URI后面加上一个”?“,”?“后面是数据,这样会导致发送的数据回显在浏览器的地址栏上(get请求在请求行上发送数据)
post请求发送数据的时候,在请求体当中发送,不会回显到浏览器的地址栏上(post请求在请求体上发送数据)
get请求无法发送大数据量,post请求可以发送大数据量,并且而理论上没有长度限制
get请求只能发送普通的字符串,并且长度有限,不同浏览器限制不同,post请求可以发送任何类型的数据,包括普通字符串和超文本
get请求在W3C中是这样说的:get请求适合于从服务器端获取数据
post请求在W3C中是这样说的:post请求适合于向服务器端传送数据
get请求是绝对安全的,因为get请求只是为了从服务器山峰获取数据,不会对服务器造成威胁
post请求是为危险的,因为post请求是向服务器提交数据,如果这些数据通过后门的方式进入到服务器中,就会对服务器造成威胁,另外post是为了提交数据,所以一般情况下拦截请求的时候,大部分会拦截post请求
get请求支持缓存
post请求不支持缓存(post请求是用来修改服务器端的资源的)
GET和POST请求应该如何选择,什么时候选择GET请求,什么时候选择POST请求
怎么向服务器发送GET请求,怎么向服务器发送POST请求
在发送数据的时候无论是get还是post,发送数据的格式都是一致的,都是用&分隔一对键和值,键和值之间使用=分隔,只是位置不同而已
public abstract class Person {
//定义核心算法
//添加了final之后,这个方法无法被覆盖,这样核心算法也就得到了保护
public final void day(){
eat();
sleep();
doSomething();
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
//可以将这个方法延伸到子类当中去
public abstract void doSomething();
}
子类1
public class Student extends Person{
@Override
public void doSomething() {
System.out.println("学生学习");
}
}
子类2
public class Teacher extends Person{
@Override
public void doSomething() {
System.out.println("老师教学");
}
}
//继承链
Servlet
----GenericServlet
----HttpServlet
GenericServlet实现了Servlet接口,在GenericServlet中有有两个service方法
源码分析结果
public class HelloServlet extends HttpServlet {
//这里重写了service方法,可以可以重写其中请求之一
/*@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("Hello");
}*/
//重写doGet方法
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.print("Get"
);
//我们发现,当重写了doGet方法,并且提交的是get请求的时候,这个方法可以处理get请求
//这个时候我试一下提交post请求
//这时候发现不能处理该请求,并且给了错误提示,同样重写doPost方法之后使用get方式提交也会出现这种错误
//出现上面的情况的原因是我只在子类中重写了doPost方法,但是你在前端提交的是get方法,但是我在子类中没有重写 //HttpServlet的
//doGet方法,那么服务器就会调用HttpServlet的doGet方法,然后就会出现错误,服务器接收到何种请求就会调用该请求 //对应的处理方法
}
}
因此我们发现,在HttpServlet中,有service方法,并且这个service方法语序被子类重写,但是被子类重写之后就不能享受网页错误提示
<welcome-file-list>
<welcome-file>login.htmlwelcome-file>
welcome-file-list>
String getParameter(String name);//使用最多的
Map<String,String[]> getParameterMap();//获取map
Enumeration<String> getParameterNames();//获取map集合中的所有key
String[] getParameterValues(String name);//根据key获取map集合的value
请求域对象
void setAttribute(String name,Object obj);//向域当中绑定数据
Object getAttribute(String name);//从域当中根据name获取数据
void removeAttribute(String name);//将域当中绑定的数据移除
//第一步:获取请求转发器对象
RequestDispatcher dispatcher = request.getRequestDispatcher("/b");
//第二步:调用转发器的forward方法完成跳转
dispatcher.getRequestDispatcher(request,response);
//当然也可以使用一行代码实现请求转发
request.getRequestDispatcher("/b").forward(request,response);
//url?username=lkw&password=123456
String username = request.getParameter("username");
Object obj = request.getAttribute("name");
//以上两个方法的区别:
//第一个方法:获取的是用户在浏览器上提交的数据
//第二个方法:获取的是请求域当中绑定的数据,就是先向请求域中设置一个数据,然后可以通过get方法获取数据
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在内,响应中文将不会出现乱码问题,就不需要设置charset=UTF-8了
//get请求的的乱码问题怎么解决?
//get请求在发送的时候,数据是在请求行上提交的,不是在请求体上提交的
//get乱码的解决方法:在CATALINA_HOME/cong/server.xml中,在Connector标签中设置如下:
<Connector URIEcoding="UTF-8" />
//注意响应的乱码问题,在tomcat8之后,URIEcoding默认即使UTF-8编码,所以GET请求也就不会出现乱码问题了
//获取应用的根路径:
String contextPath = request.getContextPath();
//获取请求方式
String method = request.getMethod();
//获取请求的URI
String uri = request.getRequestURI();// /servlet09/testrequest
//获取servlet path
String servletPath = request.getServletPath(); //testRequest
使用servlet技术对一张【部门表进行增删改查操作】
第一步:准备一张数据库表(sql脚本)
DROP TABLE IF EXISTS player;
CREATE TABLE player(
number INT,
pname VARCHAR(255),
pteam VARCHAR(255)
);
INSERT INTO player VALUES(30,'Stephen Curry','GS');
INSERT INTO player VALUES(24,'Kobe Bryant','LAL');
INSERT INTO player VALUES(7,'Kevin Druant','Net');
SELECT * FROM player;
第二步:准备前端页面
一个困扰了我一个下午的问题就是项目的包结构,就是如果以后还想开发类似的项目,那么properties配置文件应该在src下面创建一个resources文件夹,然后使用ResourceBundle类取这个配置文件中的数据的时候应该传入这样的路径:resources.jdbc(这里的jdbc是我的配置文件的名字,但是不需要加文件后缀名.properties)
在一个web应用中,有两种方式可以实现资源的跳转:
转发和重定向的区别:
代码上的区别:
//转发
request.getDispatcherServlet("/list").forward(request,response);
//转发的时候不管转发多少次都是一次请求
//重定向
response.sendRedirect("/项目名/list");
//重定向的原理是,当浏览器发送一个请求的时候,这时候目标服务器没有该资源的时候,服务器就会向浏览器发送一个路径,让浏览器主动去访问这个路径上的资源
//所以就是为什么在写路径的时候需要加上项目名,因为是浏览器是主动访问资源的
形式上的区别:
转发和重定向的本质区别
转发和重定向应该如何选择
跳转的下一个资源没有要求:
转发存在刷新页面的问题:
纯粹使用servlet编写的程序,存在很多的缺点,只要一修改代码,就需要重新编译,生成新的class问津,打一个war包,重新发布,很麻烦
于是就出现了JSP技术,就是我们程序员只需要写Servlet中的前端代码,然后让我们写的前端代码自动编译生成Servlet这种java程序,然后机器再自动将java程序编译生成class文件,然后让JVM调用这个class文件
JSP实际上是一个Servlet
jsp文件第一次访问的时候比较慢,为什么?
大部分运维人员在向客户展示项目的时候,会先把所有的jsp文件先访问一遍
第一次比较麻烦
第二次比较快
JSP是什么
对jsp进行错误调试的时候,还是要直接打开JSP文件相对应的java文件,检查java代码
jsp的page指令,解决响应的时候中文乱码的问题:
怎么在JSP中编写java程序
<%!%>
JSP的输出语句
JSP基础语法总结:
使用servlet+jsp完成项目的改造
jsp指令
指令的作用:指导jsp的翻译引擎如何工作(指导当前的jsp翻译引擎如何翻译jsp文件)
jsp指令包括:
指令的用法:
关于page指令的常用属性
<%@page session="true|false"%>
true表示启用jsp的内置对象session,表示一定启动session对象,没有session对象的时候会创建
如果没有设置,默认是session=“true”
session="false"表示不启动内置对象,当前的jsp页面无法使用内置对象session
<%@page contentType="text/html"%>contentType属性用来设置响应的内容类型
<%@page pageEncoding="UTF-8"%>
pageEncoding="UTF-8"表示响应时采用的字符集
<%@page errorPage="/error.jsp"%>
当前页面出现异常之后,跳转到error.jsp页面
errorPage属性用来指定出现错误之后跳转的位置
<%@page isError="true"%>
表示启用jsp九大内置对象的exception,默认是false
这个指令最好结合上面的errorPage使用,errorPage指令可以保证当用户的请求出错的时候,前端响应错误页面,后端出现异常,同时利于用户的体验和开发者纠错
jsp的九大内置对象
EL表达式是干什么的
EL表达式在JSP中主要是:
从某个作用域中取数据,然后将其转换成字符串,然后将其输出到浏览器,这就是EL表达式的作用
EL表达式的语法格式:
EL表达式的使用
<%
//创建user对象
User user = new User();
user.setName("lkw");
user.setAge(20);
user.setSex("男");
//将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()方法
EL表达式的这个语法中,实际调用了底层的getXxx()方法
如果没有取到数据,会报500异常
<%
//四个域中存储了数据,并且name相同
pageContext("data","pageContext");
request.setAttribute("data","request");
session.setAttribute("data","session");
application.setAttribute("data","application");
//在没有指定范围的情况下,在EL表达式中取数据优先从小范围中取数据
pageContext
EL表达式优先从小范围中取数据
EL表达式中有四个隐含的范围
EL表达式对null进行了预处理,如果是null,则向浏览器输出一个空字符串,因为设计EL表达式的初衷就是向浏览器展示数据,底层原理是先默认从最小的范围取数据,如果没有取到数据的话,会向范围大的域中依次取数据,都没有的话,不会输出任何内容
EL表达式取数据有两种形式
掌握使用EL表达式,怎么从Map集合中取数据
掌握使用EL表达式,从数组和List中取数据,使用下标的形式
page指令当中,有一个属性,可以忽略EL表达式
<%@page contentType="text/html;charset=UTF-8" isELIgnored="true"%>
isELIgnored="true",表示忽略EL表达式
isELIgnored="false",表示不忽略EL表达式(默认就是不忽略)
isELIgnored="true",这个是全局控制,就是写了这个指令,页面中的所有EL表达式都会失效
可以使用反斜杠\进行局部的控制,\${username},这样可以在想要忽略的地方忽略表达式
通过表达式获取应用的根:
EL表达式中的其他隐含对象
- 底层实际上调用的是request.getParameter()
- ```
username:
password:
//EL表达式获取表单上提交的用户名和密码
${param.username}:实际上调用的是request.getParameter("username");
${param.password}:实际上调用的是request.getParameter("password");
```
paramValue(获取请求路径中指定参数的索引值)
其底层实际上调用的是request.getParameterValues();
这个方法一般用在复选框上面,因为复选框上有多个name值相同的属性
爱好:
<input type="checkbox" name="hobby" value="sleep">睡觉
<input type="checkbox" name="hobby" value="play">玩
<input type="checkbox" name="hobby" value="eat">吃
<input type="submit" value="点击">
${paramValue.hobby[0]}//获取的是复选框上属性值为hobby的数组的第一个下标对应的值
initParam(获取初始化参数)
其底层调用的是ServletContext.getInitParameter()
![在这里插入图片描述](https://img-blog.csdnimg.cn/d342499700ab49b682d158ffa7d21ebb.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5piv5bCP5YiY5ZGAfg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)
name
刘凯武
//获取初始化参数值为name的value
${initParam.name}---->刘凯武
EL表达式的运算符
关系运算符:==、!=、> 、 < 、 >= 、<=
-逻辑运算符:!、&&、||、not、and、or
- - - - 条件运算符:? :就是三元运算符
取值运算符:[], .
empty运算符
用法:${empty 变量},结果为布尔值
<%
String name1=null;
String name2="";
List name3=new ArrayList();
pageContext.setAttribute("name1", name1);
pageContext.setAttribute("name2", name2);
pageContext.setAttribute("name3", name3);
%>
empty对于没有定义的变量,运算结果为true:
empty namex=${empty namex }
empty对于null的引用,运算结果为true:
empty name1=${empty name1 }
empty对于为空串的String引用,运算结果为true:
empty name2=${empty name2 }
empty对于没有元素的数组或集合,运算结果为true:
empty name3=${empty name3 }
empty运算可以判断一个数据是否为空,若为空,输出true,不为空,输出false
以下几种情况为空(在原本的key之前加empty关键字):
(1)值为null、空串
(2)值为Object类型的数组且长度为0 (注:其他类型的长度为0的数组值为非空)
(3)List、Map集合元素个数为0
自定义EL函数
//这个方法如果没有查到数据,就会返回null,并不会返回一个长度为0的数组
Cookie[] cookies = request.getCookies();
if(cookie != null){
//获取cookie的name
String name = cookie.getName();
//获取cookie的value
String value = cookie.getValue();
}
核心标签库:
格式化标签库:
引入标签库:
<%@ taglib url="http://java.sun.com/jsp/jstl/core" prefix="c"%>
c:if标签的使用
choose,when,otherwise标签
相当于switch语句
choose -----switch
when -----case
otherwise-----default
choose标签和otherwise标签没有属性,when标签必须有一个test属性
choose标签中必须包含至少一个when标签,可以没有otherwise标签
otherwise标签必须设置在最后一个when标签之后
choose标签只能设置when标签和otherwise标签
when标签和otherwise标签中可以嵌套其他标签
otherwisee标签会在所有when标签不执行时才会执行
foreach标签
//循环状态,可以通过循环状态获取到数组元素的下标,第几次循环,数组的首索引,尾索引
formatNumber标签
formatDate标签用于使用不同的方式将日期格式化(将Date类型转换成指定格式的字符串类型)
语法格式:
什么是过滤器:
过滤器的作用:
使用过滤器的完整流程
过滤器的实现
第一步:实现jarkata.servlet.Filter接口
第二步:重写三个方法
init:初始化过滤器
dofilter方法:这个方法是过滤器的核心方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
//处理用户请求
System.out.println("filter01正在处理请求.....");
//放行资源
filterChain.doFilter(request, response);
//这里是处理服务器的响应
System.out.println("filter01正在处理响应.....");
}
先处理用户请求,然后处理完请求之后需要放行资源,因为不放行资源的话,请求用于都不能到达服务器,放行资源:filterChain.doFilter(request,response);放行资源之后是处理服务器响应
destroy方法:销毁filter对象
第三步:在FIlter是实现类上面加一个@WebFilter(“路径”)
第四步:编写相应的servlet类接受用户请求
注意事项:关于Filter链的问题,Filter处理请求的顺序是根据项目中Filter的顺序来处理请求的,然后处理响应的时候是反过来的顺序: