xml
xml介绍
xml是可扩展的标记性语言
xml的主要作用:
- 用来保存数据,而且这些数据具有自我描述性
- 它还可以作为项目或者模块的配置文件
- 还可以作为网络传输数据的格式(现在主要是JSON)
xml元素是指从开始标签到结束标签的部分 元素可以包含其他元素、文本或者两者的混合物 元素也可以拥有属性
xml属性可以提供元素的额外信息
早期解析技术:DOM和Sax
语法
<?xml version="1.0" encoding="utf-8" ?>
<!--以上内容就是xml声明 version:xml版本 encoding:xml本身文件编码-->
<books> <!--books表示多个图书信息-->
<book sn="SN1231231231"><!--book表示一个图书信息 sn属性表示图书序列号-->
<name>超能立方</name><!--name表示书名-->
<author>水落声声</author><!--author表示作者-->
<price>10</price><!--price表示价格-->
</book>
<book sn="SN2323231123"><!--book表示一个图书信息 sn属性表示图书序列号-->
<name>照明商店</name><!--name表示书名-->
<author>姜草</author><!--author表示作者-->
<price>99</price><!--price表示价格-->
</book>
</books>
- 元素要闭合
- 大小写敏感
- 必须正确嵌套
- xml文档必须有根元素
- 属性值必须加引号
- 特殊字符
dom4j解析技术
-
创建Book类
public class Book { private String sn; private String name; private String author; private int price; public Book() { } public Book(String sn, String name, String author, int price) { this.sn = sn; this.name = name; this.author = author; this.price = price; } @Override public String toString() { return "Book{" + "sn='" + sn + '\'' + ", name='" + name + '\'' + ", author='" + author + '\'' + ", price=" + price + '}'; } public String getSn() { return sn; } public void setSn(String sn) { this.sn = sn; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public int getPrice() { return price; } public void setPrice(int price) { this.price = price; } }
-
采用dom4j解析xml
public class Dom4jTest { @Test public void test1() throws DocumentException { //创建一个SAXReader对象 去读取xml配置文件 生成Document对象 SAXReader saxReader = new SAXReader(); Document read = saxReader.read("src/com/chenxiii/javaweb/xmlFile/xml/books.xml"); System.out.println(read); //读取Books.xml生成Book类 //通过Document对象获取根元素 Element rootElement = read.getRootElement(); System.out.println(rootElement); //通过根元素获取book标签对象 element()和elements()都是通过标签名查找子元素 List<Element> books = rootElement.elements("book"); //遍历 处理每个book标签转换为Book类 for (Element book : books) { System.out.println(book.asXML()); Element nameEle = book.element("name"); String name = nameEle.getText(); //getText()获取标签中的文本内容 String price = book.elementText("price"); //elementText()获得指定标签名的文本内容 String author = book.elementText("author"); String sn = book.attributeValue("sn"); //获取属性 System.out.println(new Book(sn, name, author, Integer.parseInt(price))); } } }
JavaWeb
所有通过Java语言编写可以通过浏览器访问的程序称为JavaWeb
JavaWeb是基于请求和响应开发的
工程目录:
Servlet
- Servlet是Java EE规范之一 规范就是接口
- Servlet是JavaWeb三大组件之一 三大组件分别是:Servlet程序 Filter过滤器 Listener监听器
- Servlet是运行在服务器上的一个java小程序 它可以接受客户端发送过来的请求 并响应数据给客户端
第一个Servlet程序
-
实现Servlet接口 重写方法
public class HelloServlet implements Servlet { @Override public void init(ServletConfig servletConfig) throws ServletException { } @Override public ServletConfig getServletConfig() { return null; } // 是专门用来处理请求和响应 @Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException { System.out.println("Hello Servlet"); } @Override public String getServletInfo() { return null; } @Override public void destroy() { } }
-
配置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标签给Tomcat配置Servlet程序--> <servlet> <!--servlet-name标签 Servlet程序起一个别名 一般是类名--> <servlet-name>HelloServlet</servlet-name> <!--servlet-class 是Servlet程序的全类名--> <servlet-class>com.chenxiii.servlet.HelloServlet</servlet-class> </servlet> <!--servlet-mapping标签给servlet程序配置访问地址--> <servlet-mapping> <!--servlet-name标签是告诉服务器当前配置的地址给哪个Servlet程序使用--> <servlet-name>HelloServlet</servlet-name> <!--url-pattern配置访问地址 / 在服务器解析的时候表示地址为http://ip:port/工程路径 /hello 表示地址为http://ip:port/工程路径/hello --> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
-
常见错误
invalid url-partten xxx
:url-pattern中没有以斜杠开头servlet
的servlet-name
一定是要和servlet-mapping
中的servlet-name
一致
Servlet生命周期
- 执行Servlet构造器方法 在第一次访问创建Servlet程序的时候调用
- 执行init初始化方法 在第一次访问创建Servlet程序的时候调用
- 执行service方法 每次访问都调用
- 执行destroy销毁方法 在web工程停止的时候调用
public class HelloServlet implements Servlet {
public HelloServlet() {
System.out.println("Constructor");
}
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
}
@Override
public ServletConfig getServletConfig() {
return null;
}
// 是专门用来处理请求和响应
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
获取请求方式
// 是专门用来处理请求和响应
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("Hello Servlet");
// 类型转换 HttpServletRequest是ServletRequest的实现类 有getMethod()方法
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
//获取请求方式
String method = httpServletRequest.getMethod();
System.out.println(method);
if ("GET".equals(method)) {
doGet();
} else {
doPost();
}
}
public void doGet() {
System.out.println("get请求");
}
public void doPost() {
System.out.println("post请求");
}
HttpServlet
实际开发中很少去实现Servlet接口 一般都是继承HttpServlet类的方式去实现Servlet
public class HelloHttp extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// get请求时调用
System.out.println("HelloHttp doGet");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// post请求调用
System.out.println("HelloHttp doPost");
}
}
Servlet继承体系
ServletConfig类
Servlet程序的配置信息类
- 可以获取Servlet程序的别名 servlet-name的值
- 获取初始化参数 init-param
- 获取ServletContext对象
Servlet程序和ServletConfig对象都是由Tomcat负责 Servlet程序默认是第一次访问的时候创建 ServletConfig是每个Servlet程序创建时 就创建一个对应的ServletConfig对象
实现Servlet接口的类
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init");
//可以获取Servlet程序的别名 servlet-name的值
System.out.println("别名: " + servletConfig.getServletName());
//获取初始化参数 init-param
System.out.println("初始化参数username的值: " + servletConfig.getInitParameter("username"));
System.out.println("初始化参数password的值: " + servletConfig.getInitParameter("password"));
//获取ServletContext对象
System.out.println(servletConfig.getServletContext());
}
继承HttpServlet的类
@Override
public void init(ServletConfig config) throws ServletException {
/**
* public void init(ServletConfig config) throws ServletException {
* this.config = config;
* this.init();
* }
* GenericServlet类中的init方法 如果重写方法没有调用父类的init()方法 则无法获取ServletConfig
*/
super.init(config);// 重写父类的init(ServletConfig config)
System.out.println("重写了init方法");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// get请求时调用
System.out.println("HelloHttp doGet");
// 也可以使用ServletConfig对象 但是获取不到别的ServletConfig对象所包含的信息
ServletConfig servletConfig = getServletConfig();
}
初始化参数配置在web.xml的servlet标签中
<!--servlet标签给Tomcat配置Servlet程序-->
<servlet>
<!--servlet-name标签 Servlet程序起一个别名 一般是类名-->
<servlet-name>HelloServlet</servlet-name>
<!--servlet-class 是Servlet程序的全类名-->
<servlet-class>com.chenxiii.servlet.HelloServlet</servlet-class>
<!--init-param是初始化参数-->
<init-param>
<!--参数名-->
<param-name>username</param-name>
<!--参数值-->
<param-value>root</param-value>
</init-param>
<init-param>
<!--参数名-->
<param-name>password</param-name>
<!--参数值-->
<param-value>123456</param-value>
</init-param>
</servlet>
ServletContext类
ServletContext是一个接口 表示Servlet上下文对象
一个web工程 只有一个ServletContext对象实例
ServletContext是一个域对象(域对象是可以像Map一样存取数据的对象 这里的域是存取数据的操作范围)
- 获取web.xml中配置的上下文参数context-param
- 获取当前的工作路径 格式:/工程路径/…
- 获取工程部署后在服务器磁盘上的绝对路径
- 像Map一样存取数据
- ServletContext对象在web工程部署启动的时候创建 在web工程停止的时候销毁
// tomcat/context1
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取ServletContext对象
ServletContext context = getServletContext();
System.out.println("保存之前context中key1的值=" + context.getAttribute("key1")); //null
context.setAttribute("key1", "value1");
System.out.println("保存之后context中key1的值=" + context.getAttribute("key1")); //value1
}
// tomcat/context2
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 获取web.xml中配置的上下文参数context-param
ServletContext context = getServletConfig().getServletContext();
String username = context.getInitParameter("username");
System.out.println("username=" + username);
// 2. 获取当前的工作路径 格式:/工程路径/...
System.out.println("当前工程路径=" + context.getContextPath());
// 3. 获取工程部署后在服务器磁盘上的绝对路径
// 斜杠被解析为 http://ip:port/工程路径
System.out.println("工程部署的路径=" + context.getRealPath("/"));
// 4. 像Map一样存取数据
//先访问tomcat/context1后访问tomcat/context2则是value1
//直接访问tomcat/context2则是null
System.out.println("context中key1的值=" + context.getAttribute("key1")); //value1
}
Http协议
协议是值双方或多方相互约定好的规则
HTTP协议是指客户端和服务器之间通信时 发送的数据需要遵守的规则
HTTP传输的数据称为报文
请求的HTTP协议格式
请求分为GET请求和POST请求
GET请求:
- 请求行
- 请求的方式 GET
- 请求的资源路径[+?+请求参数]
- 请求地协议的版本号 HTTP/1.1
- 请求头
- key:value 不同的键值对表示不同的含义
POST请求
-
请求行
- 请求的方式 POST
- 请求的资源路径[+?+请求参数]
- 请求地协议的版本号 HTTP/1.1
-
请求头
-
key:value 不同的键值对表示不同的含义
空行
-
-
请求体 发送给服务器的数据
响应的HTTP协议格式
-
响应行
- 响应的协议和版本号
- 响应状态码
- 响应状态描述符
-
响应头
-
key:value 不同的键值对表示不同的含义
空行
-
-
响应体 回传给客户端的数据
常用响应码
- 200 请求成功
- 302 请求重定向
- 404 服务器已经收到但是数据不存在(地址错误)
- 500 服务器已经收到请求但是服务器内部错误
HttpServletRequest
只要每次有请求进入Tomcat服务器 Tomcat服务器就会把请求过来的HTTP协议信息解析好封装到Request对象中 然后传递到service方法(doGet和diPost) 我们可以通过HttpServletRequest对象 获取到所有请求地信息
常用API
// 获取请求的资源路径
System.out.println(request.getRequestURI());
// 获取请求的统一资源定位符 绝对路径
System.out.println(request.getRequestURL());
// 获取客户端的ip
System.out.println(request.getRemoteHost());
// 获取请求头 如User-Agent
System.out.println(request.getHeader("User-Agent"));
// 获取请求方式
System.out.println(request.getMethod());
获取参数
// 参数为表单中的name属性
String username = request.getParameter("username");
String password = request.getParameter("password");
// 获取多个值
String[] hobbies = request.getParameterValues("hobby");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.asList(hobbies));
<form action="http://localhost:8080/tomcat/para" method="get">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
兴趣爱好: <input type="checkbox" name="hobby" value="Java">Java
<input type="checkbox" name="hobby" value="Spring">Spring
<input type="checkbox" name="hobby" value="Docker">Docker
<input type="submit">
</form>
POST中文乱码
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 设置请求体的字符集为utf-8 从而解决中文乱码问题
// 该设置要在所有获取参数之前
request.setCharacterEncoding("UTF-8");
// 参数为表单中的name属性
String username = request.getParameter("username");
String password = request.getParameter("password");
// 获取多个值
String[] hobbies = request.getParameterValues("hobby");
System.out.println(username);
System.out.println(password);
System.out.println(Arrays.asList(hobbies));
}
<form action="http://localhost:8080/tomcat/para" method="post">
用户名:<input type="text" name="username">
密码:<input type="password" name="password">
兴趣爱好: <input type="checkbox" name="hobby" value="Java">Java
<input type="checkbox" name="hobby" value="Spring">Spring
<input type="checkbox" name="hobby" value="Docker">Docker
<input type="submit">
</form>
请求转发
服务器收到请求后 服务器从一个资源跳转到另一个资源
特点:
- 浏览器地址栏没有变化
- 他们是一次请求
- 他们共享Request域中的数据
- 可以转发到WEB-INF目录下 getRequestDispatcher("/WEB-INF/xxx.html") /表示web-app目录
- 不可以工程外的资源
// /servlet1
public class ServletDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
System.out.println("servlet1 username=" + username);
//设置信息
request.setAttribute("key", "info");
//转发到servlet2
//请求转发必须以/开头 /表示地址为http://ip:port/工程名
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/servlet2");
requestDispatcher.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
// /servlet2
public class ServletDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取请求参数
String username = request.getParameter("username");
System.out.println("servlet2 username=" + username);
//获取信息
Object key = request.getAttribute("key");
System.out.println("info=" + key);
//处理业务
System.out.println("servlet2 处理业务");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
HttpServletResponse
在每次请求进来 服务器会创建一个HttpServletResponse对象传递给Servlet程序使用 HttpServletRequest表示请求过来的信息 HttpServletResponse表示响应的信息
往客户端回传数据
服务器向浏览器传递字符串
public class ServletResponseDemo01 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(response.getCharacterEncoding());// 默认字符集ISO-8859-1
//设置服务器字符集
//response.setCharacterEncoding("UTF-8");
//通过响应头设置浏览器使用utf-8字符集
//response.setHeader("Content-Type", "text/html;charset=utf-8");
// 同时设置服务器和客户端都使用utf-8字符集 还设置了响应头
// 此方法一定要在获取流对象前使用才生效
response.setContentType("text/html;charset=utf-8");
// 给客户端返回字符串
PrintWriter writer = response.getWriter();
writer.write("牛逼");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
请求重定向
是指客户端给服务器发送请求 然后服务器告诉客户端 给你一个新地址 去新地址访问
特点:
- 浏览器地址栏会发生变化
- 两次请求
- 不共享Request域中的数据
- 不能访问WEB-INF目录
- 可以访问工程外的资源
// /response1
public class ServletResponseDemo02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("到此一游");
//设置响应状态码302
//response.setStatus(302);
//设置响应头
//response.setHeader("Location", "http://localhost:8080/tomcat/response3");
response.sendRedirect("http://localhost:8080/tomcat/response3");
}
}
// /response2
public class ServletResponseDemo03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("response3");
}
}
JSP
java server pages Java的服务器页面
jsp主要作用是代替Servlet程序回传html页面的数据
当我们第一次访问jsp页面时 Tomcat服务器会把jsp页面翻译成一个java源文件 并且对它编译成一个.class字节码程序
page指令
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
language:表示jsp翻译后是什么语言文件 目前只支持Java
contentType:表示jsp的返回数据类型是什么
pageEncoding:表示当前jsp页面文件本身的字符集
import:跟java源代码一样 用于导入包、类
autoFlush:设置当out输出流缓冲区满了之后 是否自动刷新缓冲区 默认值为true
buffer:设置out缓冲区大小 默认是8KB
errpage:设置当jsp页面运行时出错自动跳转去的页面路径
isErrorPage:设置当前jsp页面是否是错误信息页面 默认是false 如果是true可以获取异常信息
session:设置访问当前jsp页面 是否会创建HttpSession对象 默认是true
extends:设置jsp翻译出来的java类默认继承谁
常用脚本
声明脚本
<%! 声明java代码 %>
可以给jsp翻译出来的java类定义属性和方法甚至是静态代码块、内部类等。
<body>
<%--声明类的属性--%>
<%!
private Integer id;
private String name;
private static Map<String, Object> map;
%>
<%--声明static静态代码块--%>
<%!
static {
map = new HashMap<String, Object>();
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}
%>
<%--声明类方法--%>
<%!
public int abc() {
return 12;
}
%>
<%--声明内部类--%>
<%!
public static class A {
private int id = 3;
}
%>
</body>
表达式脚本
<%=表达式%>
作用:在jsp页面上输出数据
<%--输出整型--%>
<%=12%>
<%--输出浮点型--%>
<%=12.0%>
<%--输出字符串--%>
<%="字符串"%>
<%--输出对象--%>
<%="字符串也是对象"%>
- 所有的表达式脚本都会被翻译带_jspService()方法中
- 表达式脚本都会被翻译成out.print()输出到页面上
- 由于所有的表达式脚本都会被翻译带_jspService()方法中 所以jspService()中对象都可以直接使用
- 表达式脚本不能以分号结束
代码脚本
<%
java语句
%>
作用:可以在jsp页面中 编写我们自己需要的功能
<%
int i = 12;
if (i == 12) {
System.out.println("牛逼");
}
for (int j = 0; j < 5; j++) {
System.out.println("很牛逼");
}
// 翻译后java文件中_jspService方法内的代码都可以写
String username = request.getParameter("username");
System.out.println("username=" + username);
%>
- 代码脚本翻译后都在_jspService方法中
- 由于代码脚本翻译后都在_jspService方法中 所以方法内对象都可以使用
- 代码脚本还可以由多个代码脚本块组合完成一个java语句
- 代码脚本还可以和表达式脚本一起组合使用 在jsp界面上输出数据
三种注释
<!--html注释-->
html注释会被翻译到java源代码中 在_jspService方法里 以out.write输出到客户端
<%
// 单行java注释
/*
多行java注释
*/
%>
java注释会被翻译到java源代码中
<%--jsp注释--%>
jsp注释可以注释掉jsp页面中所有代码
jsp九大内置对象
jsp中的内置对象是指tomcat在翻译jsp页面成为Servlet源代码后 内部提供的九大对象 叫做内置对象
jsp四大域对象
- pageContext (PageContextImpl类) 当前jsp页面范围内有效
- request (HttpServletRequest类) 一次请求内有效
- session (HttpSession类) 一个会话范围内有效(打开浏览器访问服务器,直到关闭浏览器)
- application (ServletContext类) 整个web工程范围内有效(只要web工程不停止 数据都在)
域对象是可以像Map一样存取数据的对象 四个域对象功能一样 不同的是它们对数据的存取范围
四个域在使用的时候 优先顺序是按从小到大排列的
<body>
<%
pageContext.setAttribute("key", "pageContext");
request.setAttribute("key", "request");
session.setAttribute("key", "session");
application.setAttribute("key", "application");
%>
pageContext域是否有值<%=pageContext.getAttribute("key")%><br>
request域是否有值<%=request.getAttribute("key")%><br>
session域是否有值<%=session.getAttribute("key")%><br>
application域是否有值<%=application.getAttribute("key")%><br>
</body>
out和response.getWriter输出的区别
由于jsp翻译之后 底层源代码都是使用out来进行输出 所以一般情况下 使用out来输出 避免打乱页面输出内容的顺序
jsp的常用标签
静态包含
- 静态包含不会翻译被包含的jsp界面
- 静态包含其实是把被包含的jsp界面的代码拷贝到包含的位置执行输出
main.jsp
<body>
头部信息<br>
主题信息<br>
<%--
<%@include file=""%> 就是静态包含
file属性指定你要包含的jsp页面路径
地址中的一个/表示 http://ip:port/工程路径 映射到代码的web目录
--%>
<%@include file="footer.jsp"%>
</body>
footer.jsp
<body>
底部信息<br>
</body>
动态包含
- 动态包含会把包含的jsp页面也翻译成为jsp代码
- 动态包含底层代码调用方法调用被包含的jsp页面执行
- 动态包含还可以传递参数
<%--
page属性指定你要包含的jsp界面
动态包含也可以像静态包含一样 把被包含的内容执行输出到包含位置
--%>
<jsp:include page="/include/footer.jsp">
<jsp:param name="username" value="zhangsan"/>
</jsp:include>
<body>
底部信息<br>
<%=request.getParameter("username")%>
</body>
转发
<%--
<jsp:forward page=""></jsp:forward> 请求转发标签 功能是请求转发
page属性设置请求转发路径
--%>
<jsp:forward page="scope2.jsp"></jsp:forward>
Listener监听器
Listener监听器是Javaweb的三大组件之一 三大组件分别是:Servlet程序 Filter过滤器 Listener监听器
Listener它是Java EE的规范 就是接口
监听器的作用是监听某种事物的变化 然后通过回调函数 反馈给客户去做一些相应的事
ServletContextListener
ServletContextListener可以监听ServletContext的创建和销毁
ServletContext对象在web工程启动的时候创建 在web工程停止的时候销毁
监听到创建和销毁之后都会分别调用ServletContext的监听器方法反馈
-
编写一个类实现ServletContextListener
-
实现其两个方法
public class MyServletContextListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("ServletContext对象创建"); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("ServletContext对象销毁"); } }
-
到web.xml中配置监听器
<listener> <listener-class>com.chenxiii.jsp.listener.MyServletContextListener</listener-class> </listener>
EL表达式
简介
Expression Language 是表达式语言
作用:主要是替代jsp页面中的表达式脚本 在jsp页面中进行数据的输出 因为EL表达式在输出数据的时候 要比jsp表达式脚本简洁的多
<%
request.setAttribute("key", "value");
%>
表达式脚本输出:<%=request.getAttribute("key")%><br/>
EL表达式输出:${key}
若key值找不到则 EL表达式在输出null时输出空串 JSP表达式输出null
当四个域中都有相同key的数据的时候 EL表达式会按照四个域的大小从小到大去进行搜索
EL表达式输出Bean对象
<%
Person person = new Person();
person.setName("牛逼");
person.setPhones(new String[]{"123123", "123123123123"});
List<String> cities = new ArrayList<>();
cities.add("beijing");
cities.add("hangzhou");
person.setCities(cities);
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
person.setMap(map);
pageContext.setAttribute("p", person);
%>
输出Person: ${p}<br/>
输出Person的name属性: ${p.name}<br/>
输出Person的phones属性: ${p.phones[0]}<br/>
输出Person的list属性: ${p.cities}<br/>
输出Person的list属性个别元素: ${p.cities[0]}<br/>
输出Person的map属性: ${p.map}<br/>
输出Person的map属性个别元素: ${p.map.key1}<br/>
EL表达式找的不是属性 而是属性的get方法
运算
关系运算
${12 == 12}<br/>
${12 eq 12}<br/
逻辑运算
${12 eq 12 && 12 lt 11}<br/>
${12 == 12 || 12 > 11}<br/>
${12 eq 12 and 12 lt 11}<br/>
${12 == 12 or 12 > 11}<br/>
算术运算
${12 + 13}<br/>
empty运算 可以判断数据是否为空 为空输出true
<%
// 以下情况为true
/*值为null的时候*/
request.setAttribute("emptyNull", null);
/*值为空串的时候*/
request.setAttribute("emptyStr", "");
/*值是Object类型数组 长度为0的时候*/
request.setAttribute("emptyArr", new Object[]{});
/*list集合 元素个数为0*/
List<String> list = new ArrayList<>();
request.setAttribute("emptyList", list);
/*map集合 元素个数为0*/
Map<String, Object> emptyMap = new HashMap<>();
request.setAttribute("emptyMap", emptyMap);
%>
${empty emptyNull}<br/>
${empty emptyStr}<br/>
${empty emptyArr}<br/>
${empty emptyList}<br/>
${empty emptyMap}<br/>
三元运算
<%--牛逼--%>
${12 == 12 ? "牛逼" : "不牛逼"}
点运算和[]运算
点运算可以输出Bean对象中某个属性的值
[]运算可以输出有序集合中某个元素的值 还可以输出map集合中key里含有特殊字符的key值
输出Person: ${p}<br/>
输出Person的name属性: ${p.name}<br/>
输出Person的phones属性: ${p.phones[0]}<br/>
11个隐含对象
变量 | 类型 | 作用 |
---|---|---|
pageContext | PageContextlmpl | 它可以获取jsp中的九大内置对象 |
pageScope | Map<String,Object> | 它可以获取pageContext域中的数据 |
requestScope | Map<String,Object> | 它可以获取Request域中的数据 |
sessionScope | sessionScope | 它可以获取Session域中的数据 |
applicationScope | Map<String,Object> | 它可以获取ServletContext域中的数据 |
param | Map<String,String> | 它可以获取请求参数的值 |
paramValues | Map<String,String[]> | 它也可以获取请求参数的值,获取多个值的时候使用。 |
header | Map<String,String> | 它可以获取请求头的信息 |
headerValues | Map<String,String[]> | 它可以获取请求头的信息,它可以获取多个值的情况 |
cookie | Map<String,Cookie> | 它可以获取当前请求的Cookie信息 |
initParam | Map<String,String> | 它可以获取在web.xml中配置的context-param上下文参数 |
JSTL
JSTL 标签库 全称是指 JSP Standard Tag Library JSP 标准标签库。是一个不断完善的开放源代码的 JSP 标 签库。
EL 表达式主要是为了替换 jsp 中的表达式脚本,而标签库则是为了替换代码脚本。这样使得整个 jsp 页面 变得更佳简洁。
功能范围 | URI | 前缀 |
---|---|---|
核心标签库–重点 | http://java.sun.com/jsp/jstl/core | c |
格式化 | http://java.sun.com/jsp/jstl/fmt | fmt |
函数 | http://java.sun.com/jsp/jstl/functions | fn |
数据库(不使用) | http://java.sun.com/jsp/jstl/sql | sql |
XML(不使用) | http://java.sun.com/jsp/jstl/xml | x |
jsp标签库中使用taglib指令引入标签库
CORE 标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
XML 标签库
<%@ taglib prefix="x" uri="http://java.sun.com/jsp/jstl/xml" %>
FMT 标签库
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
SQL 标签库
<%@ taglib prefix="sql" uri="http://java.sun.com/jsp/jstl/sql" %>
FUNCTIONS 标签库
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
核心库
c:set
作用:可以往域中保存数据
<%--
<c:set />
作用:set 标签可以往域中保存数据域对象.setAttribute(key,value);
scope 属性设置保存到哪个域
page 表示 PageContext 域(默认值)
request 表示 Request 域
session 表示 Session 域
application 表示 ServletContext 域
var 属性设置 key 是多少
value 属性设置值
--%>
保存之前:${requestScope.abc}<br/>
<c:set scope="request" var="abc" value="牛逼"/>
保存之后:${requestScope.abc}<br/>
c:if
作用:用来做if判断
<%--
<c:if />
if 标签用来做 if 判断。
test 属性表示判断的条件(使用 EL 表达式输出)
--%>
<c:if test="${12 == 12}">
<h1>真牛逼</h1>
</c:if>
c:choose c:when c:otherwise
作用:多路判断 跟switch相似
<%--
<c:choose> <c:when> <c:otherwise>标签
作用:多路判断。跟 switch ... case .... default 非常接近
choose 标签开始选择判断
when 标签表示每一种判断情况
test 属性表示当前这种判断情况的值
otherwise 标签表示剩下的情况
<c:choose> <c:when> <c:otherwise>标签使用时需要注意的点:
1、标签里不能使用 html 注释,要使用 jsp 注释
2、when 标签的父标签一定要是 choose 标签
--%>
<%
request.setAttribute("height", 178);
%>
<c:choose>
<c:when test="${requestScope.height > 190}">
<h2>好高</h2>
</c:when>
<c:when test="${requestScope.height > 180}">
<h2>有点高</h2>
</c:when>
<c:otherwise>
<h2>还可以</h2>
</c:otherwise>
</c:choose>
c:forEach
<%--
遍历 1 到 10,输出
begin 属性设置开始的索引
end 属性设置结束的索引
var 属性表示循环的变量(也是当前正在遍历到的数据)
for (int i = 1; i < 10; i++)
--%>
<c:forEach begin="1" end="10" var="i">
${i}<br/>
</c:forEach>
文件上传
- 要有一个 form 标签,method=post 请求
- form 标签的 encType 属性值必须为 multipart/form-data 值
- 在 form 标签中使用 input type=file 添加上传的文件
- 编写服务器代码(Servlet 程序)接收,处理上传的数据。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="http://localhost:8080/tomcat/upload" method="post" enctype="multipart/form-data">
用户名: <input type="text" name="username">
头像: <input type="file" name="photo">
<input type="submit" value="上传">
</form>
</body>
</html>
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 导入commons-upload.jar commons-io.jar
// 1.判断上传的数据是否是多段数据(只有多段的数据 才是文件上传)
if(ServletFileUpload.isMultipartContent(req)) {
// 创建FileItemFactory工厂实现类
FileItemFactory factory = new DiskFileItemFactory();
// 创建用于解析上传数据的工具类ServletFileUpload类
ServletFileUpload servletFileUpload = new ServletFileUpload(factory);
//解析上传的数据得到每一个表单项
try {
List<FileItem> fileItems = servletFileUpload.parseRequest(req);
//判断每一个表单项是普通类型还是上传的文件
for (FileItem fileItem : fileItems) {
if (fileItem.isFormField()) {
// 普通表单项
System.out.println("表单项的name属性值:" + fileItem.getFieldName());
// 参数utf-8解决乱码问题
System.out.println("表单项的value属性值:" + fileItem.getString("UTF-8"));
} else {
// 上传的文件
System.out.println("表单项的name属性值:" + fileItem.getFieldName());
// 参数utf-8解决乱码问题
System.out.println("文件名:" + fileItem.getName());
fileItem.write(new File("e:\\" + fileItem.getName()));
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
HTTP协议说明
API说明
ServletFileUpload 类,用于解析上传的数据。
FileItem 类,表示每一个表单项。
boolean ServletFileUpload.isMultipartContent(HttpServletRequest request);
判断当前上传的数据格式是否是多段的格式。
public List<FileItem> parseRequest(HttpServletRequest request)
解析上传的数据
boolean FileItem.isFormField()
判断当前这个表单项,是否是普通的表单项。还是上传的文件类型。
true 表示普通类型的表单项
false 表示上传的文件类型
String FileItem.getFieldName()
获取表单项的 name 属性值
String FileItem.getString()
获取当前表单项的值。
String FileItem.getName();
获取上传的文件名
void FileItem.write( file );
将上传的文件写到 参数 file 所指向抽硬盘位置 。
文件下载
- 获取要下载的文件名
- 读取要下载的文件内容
- 把下载的文件内容回传到客户端
- 在回传前 通过响应头告诉客户端返回的数据类型
- 通过响应头告诉客户端收到的数据用于下载使用
public class DownloadServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String downloadFileName = "1.png";
// 读取下载文件内容 通过ServletContext对象
ServletContext servletContext = req.getServletContext();
// 获取要下载的文件类型
String mimeType = servletContext.getMimeType("/file/" + downloadFileName);
System.out.println(mimeType);
// 通过响应头告诉客户端返回的数据类型
resp.setContentType(mimeType);
// 通过响应头告诉客户端数据是用于下载的
//"Content-Disposition" 表示收到的数据怎么处理
//attachment表示附件 表示下载使用
//filename= 表示指定下载的文件名
//url编码是把汉字转换为%xx%xx格式
resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("美少女.png", "UTF-8"));
// /被服务器解析表示地址http://ip:port/工程名/ 映射到代码的webapp目录
InputStream is = servletContext.getResourceAsStream("/file/" + downloadFileName);
// 获取响应的输出流
OutputStream os = resp.getOutputStream();
// 读取输入流中的全部数据 赋值给输出流 输出到客户端
IOUtils.copy(is, os);
}
}
Cookie
是服务器通知客户端保存键值对的一种技术
客户端有了Cookie后 每次请求都发送给服务器
每个Cookie的大小不超过4kb
创建Cookie
// 创建Cookie对象
Cookie cookie = new Cookie("key", "value");
Cookie cookie2 = new Cookie("key2", "value2");
//通知客户端保存cookie
resp.addCookie(cookie);
resp.addCookie(cookie2);
resp.getWriter().write("cookie 创建成功");
Cookie获取
服务器获取
Cookie[] cookies = req.getCookies(); //获取全部Cookie
并没有直接获取某个Cookie的方法 只有遍历查找
public static Cookie findCookie(String name, Cookie[] cookies) {
if (name == null || cookies == null || cookies.length == 0) {
return null;
}
for (Cookie cookie : cookies) {
if (name.equals(cookie.getName())) {
return cookie;
}
}
return null;
}
Cookie值修改
方法一:
//创建同名的Cookie 在构造器中赋予新的值
Cookie cookie = new Cookie("key", "value333");
//传递给客户端 通知客户端保存修改
resp.addCookie(cookie);
方法二:
//查找需要修改的Cookie对象
Cookie cookie = CookieUtils.findCookie("key", req.getCookies());
//调用setValue方法赋予新值
if (cookie != null) {
cookie.setValue("Cookie888");
//通知客户端保存修改
resp.addCookie(cookie);
}
注:Cookie不包含空格 方括号 圆括号 等号 逗号 双引号 斜杠 问号 冒号 分号 中文等
Cookie存活
设置默认Cookie
protected void defaultLife(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// setMaxAge()
// 正数 指定秒数后过期
// 负数 关闭浏览器删除
// 0 立刻删除
Cookie cookie = new Cookie("life", "life");
cookie.setMaxAge(-1);
resp.addCookie(cookie);
}
立刻删除Cookie
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// setMaxAge()
// 正数 指定秒数后过期
// 负数 关闭浏览器删除
// 0 立刻删除
Cookie cookie = CookieUtils.findCookie("key2", req.getCookies());
if (cookie!= null) {
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
}
指定存活时间
protected void live(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// setMaxAge()
// 正数 指定秒数后过期
// 负数 关闭浏览器删除
// 0 立刻删除
Cookie cookie = new Cookie("live", "3600");
cookie.setMaxAge(10);
resp.addCookie(cookie);
}
Path属性
可以有效过滤哪些Cookie可以发送给服务器 哪些不发
path请求的地址来进行有效的过滤
protected void pathCookie(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie = new Cookie("path1", "path1");
//req.getContextPath()得到工程路径
cookie.setPath(req.getContextPath() + "/abc");
//"工程路径 + /abc" 可以访问Cookie
resp.addCookie(cookie);
}
Session
是一个接口( HttpSession )
是一个会话 用来维护一个客户端和服务器之间关联的一种技术
每个客户端都有自己的一个Session会话
Session会话中 经常用来保存用户登录之后的信息
创建Session和获取
protected void createOrGetSession(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建和获取Session对象 第一次是创建新的 之后都是获取之前的Session
HttpSession session = req.getSession();
//判断是否是新创建出来的
boolean aNew = session.isNew();
//获取Session会话的唯一标识id
String id = session.getId();
resp.getWriter().write("Session id=" + id + "<br />");
resp.getWriter().write("Session isNew=" + aNew + "<br />");
}
Session域中数据的存取
protected void getAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object key = req.getSession().getAttribute("key");
resp.getWriter().write("key=" + key);
}
protected void setAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("key", "value");
}
Session生命周期
在Tomcat服务器配置文件web.xml中默认时长为30分钟
protected void defaultLife(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取默认超时时长
int max = req.getSession().getMaxInactiveInterval();
resp.getWriter().write("默认超时时长=" + max); //默认超时时长=1800
}
在web.xml中设置默认时长 设置所有Session默认时长为20分钟
<session-config>
<session-timeout>20</session-timeout>
</session-config>
只修改个别Session的超时时长 Session超时是指客户端两次请求的最大间隔时长
protected void life3(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置当前Session3秒后超时
//负数表示永不超时(极少使用)
req.getSession().setMaxInactiveInterval(3);
}
让Session会话马上超时
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置Session会话马上超时
req.getSession().invalidate();
}
浏览器和Session之间关联的技术内幕
Session技术底层其实是基于Cookie技术实现的
iter().write(“Session id=” + id + “
”);
resp.getWriter().write(“Session isNew=” + aNew + “
”);
}
### Session域中数据的存取
```java
protected void getAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Object key = req.getSession().getAttribute("key");
resp.getWriter().write("key=" + key);
}
protected void setAttribute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HttpSession session = req.getSession();
session.setAttribute("key", "value");
}
Session生命周期
在Tomcat服务器配置文件web.xml中默认时长为30分钟
protected void defaultLife(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取默认超时时长
int max = req.getSession().getMaxInactiveInterval();
resp.getWriter().write("默认超时时长=" + max); //默认超时时长=1800
}
在web.xml中设置默认时长 设置所有Session默认时长为20分钟
<session-config>
<session-timeout>20</session-timeout>
</session-config>
只修改个别Session的超时时长 Session超时是指客户端两次请求的最大间隔时长
protected void life3(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置当前Session3秒后超时
//负数表示永不超时(极少使用)
req.getSession().setMaxInactiveInterval(3);
}
[外链图片转存中…(img-iwiXQSnk-1634828158770)]
让Session会话马上超时
protected void deleteNow(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置Session会话马上超时
req.getSession().invalidate();
}
浏览器和Session之间关联的技术内幕
Session技术底层其实是基于Cookie技术实现的
[外链图片转存中…(img-IIFZSdeB-1634828158770)]
Filter
是三大组件之一
是Java EE的规范 也就是接口
作用:拦截请求 过滤相应
场景:
- 权限检查
- 日记操作
- 事务管理
基本使用
编写一个类实现Filter接口 实现过滤方法doFilter
public class AdminFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
// 专门用于拦截请求 可以做权限检查
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤器执行");
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
HttpSession session = httpServletRequest.getSession();
Object user = session.getAttribute("user");
if (user == null) {
servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
return;
} else {
//让程序继续访问目标资源
filterChain.doFilter(servletRequest, servletResponse);
}
}
@Override
public void destroy() {
}
}
配置Filter
<!--配置一个过滤器-->
<filter>
<!--给filter起别名-->
<filter-name>AdminFilter</filter-name>
<!--配置filter的全类名-->
<filter-class>com.chenxiii.filter.AdminFilter</filter-class>
</filter>
<!--配置Filter过滤器的拦截路径-->
<filter-mapping>
<!--表示当前的拦截器给哪个filter使用-->
<filter-name>AdminFilter</filter-name>
<!--配置拦截路径-->
<!--/ 表示http://ip:port/工程路径/-->
<!--/admin/* 表示http://ip:port/工程路径/admin/ 目录下全部文件-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
生命周期
- 构造器方法 在web工程启动时执行
- init 初始化方法 在web工程启动时执行
- doFilter 过滤方法 每次拦截到请求执行
- destroy 销毁 web工程停止时执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-swG9YOvf-1635087439787)(javaweb2.assets/image-20211024204531243.png)]
FilterConfig类
Tomcat在每次创建Filter时 会同时创建一个FilterConfig类 包含了Filter配置文件的配置信息
作用:获取配置器的内容
- 获取Filter的别名 filter-name
- 获取在Filter中配置的 init-param 初始化参数
- 获取ServletContext对象
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("2.初始化方法");
System.out.println("filter-name=" + filterConfig.getFilterName());//filter-name=AdminFilter
System.out.println("初始化参数param = " + filterConfig.getInitParameter("username"));//初始化参数param = zhangsan
System.out.println(filterConfig.getServletContext());//org.apache.catalina.core.ApplicationContextFacade@10f4a20f
}
参数配置
<!--配置一个过滤器-->
<filter>
<!--给filter起别名-->
<filter-name>AdminFilter</filter-name>
<!--配置filter的全类名-->
<filter-class>com.chenxiii.filter.AdminFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>zhangsan</param-value>
</init-param>
</filter>
<!--配置Filter过滤器的拦截路径-->
<filter-mapping>
<!--表示当前的拦截器给哪个filter使用-->
<filter-name>AdminFilter</filter-name>
<!--配置拦截路径-->
<!--/ 表示http://ip:port/工程路径/-->
<!--/admin/* 表示http://ip:port/工程路径/admin/ 目录下全部文件-->
<url-pattern>/admin/*</url-pattern>
</filter-mapping>
FilterChain 过滤器链
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("前置1111111");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("后置33333");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("前置222222");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("后置44444");
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gq9RwEYS-1635087439789)(javaweb2.assets/image-20211024210342003.png)]
若 Filter2 中没有后置代码 则直接执行Filter1的后置代码
在多个Filter过滤器执行的时候 执行顺序是在web.xml中从上到下的顺序
多个Filter过滤器执行的特点:
- 所有Filter和目标资源都默认执行在同一个线程中
- 多个Filter共同执行的时候 使用同一个Request对象 Request域中数据共享
拦截路径
-
精确匹配
<url-pattern>/chain/a.jsp</url-pattern>
-
目录匹配
<url-pattern>/admin/*</url-pattern>
-
后缀名匹配 不能 / 开头
<url-pattern>*.html</url-pattern>
Filter过滤器只关心地址是否匹配 不关心资源是否存在