1.servlet
- Servlet 是运行在 Web 服务器或应用服务器上的程序,其实也就是一个包装了浏览器的请求对象和服务器响应对象的一个java类,方便实现浏览器对服务器的请求和服务器对浏览器响应的一个工具类。
- Servlet 只用来扩展基于 HTTP 协议的 Web 服 务器
- 服务器可以自动根据请求执行相应的servlet进行请求处理
- servlet的实现:java类继承HttpServlet,重写service方法
数据流转流程:
浏览器------>服务器------->数据库
浏览器<------服务器<-------数据库
servlet实现流程:
浏览器发送请求到服务器,服务器根据请求URL地址 中的URI信息在webapps目录下找到对应的项目文件夹, 然后在web.xml中检索对应的servlet,找到后调用并执行 Servlet。
servlet生命周期:
- 从第一次调用到服务器关闭。
- 如果在web.xml中配置了load-on-startup,生命周期为从服务器启动到服务器关闭
内置对象:
request对象:服务器接收到浏览器请求后,自行创建一个request对象用于存储请求信息
获取请求头数据
* req.getMethod(); 获取请求方式
* req.getRequestURL() 获取请求URL
* req.getRequestURI();获取请求URI
* req.getScheme(); 获取协议
* 获取请求行数据
* req.getHeader("aaa"); 获取指定的请求行信息
* req.getHeaderNames(); 获取所有请求行的键名
* 获取用户数据
* req.getParameter("uname"); 获取指定用户数据
* req.getParameterValues("hoby"); 获取单键多值的用户数据(多选)
* req.getParameterNames(); 获取所有的用户数据的键名
* 注意:request对象由tomcat创建
response对象:由服务器创建,用于存储响应信息
//设置响应头
resp.setHeader("mouse","tdw"); //会覆盖
resp.addHeader("key","zfh"); //不会覆盖
resp.addHeader("key","fcd");
//设置响应编码格式
//resp.setHeader("content-type","text/html;charset=utf-8");
//resp.setContentType("text/plain;charset=utf-8"); //所有文本
//resp.setContentType("text/xml;charset=utf-8"); //xml文本
resp.setContentType("text/html;charset=utf-8"); //html文本
//设置响应状态码
//resp.sendError(404,"this Method is not supported");
//设置相应主体
resp.getWriter().print("<b>ttttt</b>");
ServletContext 对象:由服务器进行创建,一个项目只有一个对
象。不管在项目的任意位置进行获取得到的都是同一个对象,那
么不同用户发起的请求获取到的也就是同一个对象了,该对象由
用户共同拥有。
/**
* ServletContext对象学习:
* 问题:
* 不同的用户使用相同的数据
* 解决:
* ServletContext对象
* 特点:
* 服务器创建
* 用户共享
* 作用域:
* 整个项目内
* 生命周期:
* 服务器启动到服务器关闭
* 使用:
* 获取ServletContext对象
* //第一种方式:
ServletContext sc=this.getServletContext();
//第二种方式:
ServletContext sc2=this.getServletConfig().getServletContext();
//第三种方式:
ServletContext sc3=req.getSession().getServletContext();
* 使用ServletContext对象完成数据共享
* //数据存储
* sc.setAttribute(String name, Object value);
* //数据获取
* sc.getAttribute("str") 返回的是Object类型
* 注意:
* 不同的用户可以给ServletContext对象进行数据的存取。
* 获取的数据不存在返回null。
* 获取项目中web.xml文件中的全局配置数据
* sc.getInitParameter(String name); 根据键的名字返回web.xml中配置的全局数据的值,返回String类型。
* 如果数据不存在返回null。
* sc.getInitParameterNames();返回键名的枚举
* 配置方式:注意 一组<context-param>标签只能存储一组键值对数据,多组可以声明多个 <context-param>进行存储。
* <context-param>
<param-name>name</param-name>
<param-value>zhangsan</param-value>
</context-param>
作用:将静态数据和代码进行解耦。
获取项目webroot下的资源的绝对路径。
String path=sc.getRealPath(String path);
获取的路径为项目根目录,path参数为项目根目录中的路径
获取webroot下的资源的流对象
InputStream is = sc.getResourceAsStream(String path);
注意:
此种方式只能获取项目根目录下的资源流对象,class文件的流对象需要使用类加载器获取。
path参数为项目根目录中的路径
*
*/
@WebServlet(name = "servletContext")
public class servletContext extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取ServletContext对象
//方式一
ServletContext sc = this.getServletContext();
//方式二
//ServletContext sc = this.getServletConfig().getServletContext();
//方式三
//ServletContext sc = req.getSession().getServletContext();
//数据存储
sc.setAttribute("str","值");
//web.xml配置全局数据获取
String name = sc.getInitParameter("name");
System.out.println(name);
Enumeration<String> names = sc.getInitParameterNames();
//获取路径
String path = sc.getRealPath("/lib");
System.out.println(path);
//获取项目根目录下的资源流对象
InputStream rs = sc.getResourceAsStream("/usr/1.txt");
}
}
servletConfig对象:
ServletConfig 对象:
问题:
使用ServletContext对象可以获取web.xml中的全局配置文件,在 web.xml中每个 Servlet 也可以进行单独的配置,那么该怎么获取配置信息呢?
解决:使用 ServletConfig 对象
作用:ServletConfig 对象是 Servlet 的专属配置对象,每个 Servlet 都单独拥有一个 ServletConfig 对象,用来获取 web.xml 中的配置信息。
使用:
获取 ServletConfig 对象
获取 web.xml 中 servlet 的配置信息
web.xml配置:
一个完整servlet的所需配置
<servlet>
<servlet-name>serLoad</servlet-name>
<servlet-class>com.idea.servlet.Servletload</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>serLoad</servlet-name>
<url-pattern>/serLoad</url-pattern>
</servlet-mapping>
请求转发&重定向
请去转发:为一次请求,其中request&response对象可以数据共享
req.getRequestDispatcher("").forward(req,resp);
请求转发到的servlet实现页面跳转应基于第一次实现请求转发前的页面重定向为:为两次请求,request&response无法实现数据共享,数据共享依赖cookie&session存储技术
resp.sendRedirect("");
cookie 技术其实是浏览器端的数据存储技术,解决了不同请求
需要使用相同的请求数据的问题。。
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Cookie 技术:
* 使用:
* //创建Cookie对象
* //设置cookie
* //设置有效期
* //设置有效路径
* //响应Cookie对象给客户端
* //获取cookie信息
* Cookie[] cs = req.getCookies();
* if(cs!=null){
* for(Cookie c:cs){
* String name = c.getName();
* String value = c.getValue();
* System.out.println(name+":"+value);
* }
* }
* 注意:
* 一个cookie对象存储一条数据,多条数据可以使用多个cookie对象存储
* 特点:
* 浏览器端的数据存储技术
* 适合少量数据
* 键值对
* 不安全
* 临时存储:存储在浏览器运行内存中,浏览器关闭即失效
* 定时存储:设置了Cookie的有效期,存储在客户端的硬盘中,在有效期时间内符合路径要求的请求都会附带该信息
* 默认:cookie信息存储后每次都会附带,除非进行设置
*/
@WebServlet(name = "CookieServlet")
public class CookieServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置响应编码格式
resp.setContentType("text/html;charset=utf-8");
//获取请求信息
//处理请求信息
//响应处理结果
//使用Cookie进行浏览器端的数据存储
//创建Cookie对象
Cookie c = new Cookie("str","mouse");
Cookie c2 = new Cookie("str2","name");
//设置Cookie
//设置Cookie有效期
c.setMaxAge(3*24*3600);//以秒为单位
//设置有效路径
c.setPath("/cooSer/abc");
//响应Cookie
resp.addCookie(c);
//直接响应resp.addCookie(c2);
//请求转发
//重定向
resp.getWriter().write("Cookie");
}
}
Session是存在服务器的一种用来存放用户数据的类HashTable结构
/**
* session技术学习:
* 问题:
* 一个用户的不同请求处理的数据共享怎么办?
* 解决:
* 使用session技术
* 原理:
* 用户第一次访问服务器,服务器会创建一个session对象给此用户,并将
* 该session对象的JSESSIONID使用Cookie技术存储到浏览器中,保证
* 用户的其他请求能够获取到同一个session对象,也保证了不同请求能够获取到
* 共享的数据。
* 特点:
* 存储在服务器端
* 服务器进行创建
* 依赖Cookie技术
* 一次会话
* 默认存储时间是30分钟
* 作用:
* 解决了一个用户不同请求处理的数据共享问题
* 使用:
* 创建session对象/获取session对象
HttpSession hs=req.getSession();
如果请求中拥有session的标识符也就是JSESSIONID,则返回其对应的session对象
如果请求中没有session的标识符也就是JSESSIONID,则创建新的session对象,并将其JSESSIONID作为从cookie数据存储到浏览器内存中
* 如果session对象是失效了,也会重新创建一个session对象,并将其JSESSIONID存储在浏览器内存中。
* 设置session存储时间
* hs.setMaxInactiveInterval(int seconds);
* 注意:
* 在指定的时间内session对象没有被使用则销毁,如果使用了则重新计时。
* 设置session强制失效
* hs.invalidate();
* 存储和获取数据
* 存储:hs.setAttribute(String name,Object value);
* 获取:hs.getAttribute(String name) 返回的数据类型为Object
* 注意:
* 存储的动作和取出的动作发生在不同的请求中,但是存储要先于取出执行。
* 使用时机:
* 一般用户在登陆web项目时会将用户的个人信息存储到Sesion中,供该用户的其他请求使用。
* 总结:
* session解决了一个用户的不同请求的数据共享问题,只要在JSESSIONID不失效和session对象不失效的情况下。
* 用户的任意请求在处理时都能获取到同一个session对象。
* 作用域:
* 一次会话
* 在JSESSIONID和SESSION对象不失效的情况下为整个项目内。
* session失效处理:
* 将用户请求中的JSESSIONID和后台获取到的SESSION对象的JSESSIONID进行比对,如果一致
* 则session没有失效,如果不一致则证明session失效了。重定向到登录页面,让用户重新登录。
* 注意:
* JSESSIONID存储在了Cookie的临时存储空间中,浏览器关闭即失效。
*/
@WebServlet(name = "SessionServlet")
public class SessionServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求编码格式
req.setCharacterEncoding("utf-8");
//设置相应编码格式
resp.setContentType("text/html;charset=utf-8");
//获取请求数据
//创建session对象/获取session对象
HttpSession se = req.getSession();
String name = "张三";
se.setAttribute("name",name);
System.out.println(se.getId());
//处理请求数据
//相应处理结果
//直接响应
resp.getWriter().write("session");
//请求转发
//重定向
}
}
EL表达式
<%--
传统方式获取作用域数据:
缺点一:导入包
缺点二:需要强转
缺点三:获取数据的代码过于麻烦。
使用El表达式获取作用域数据:
作用:获取作用域对象中的数据。
注意:获取的是pageContext、request、session、application四个对象中的数据,其他数据一概不理会。
找到了则获取返回,找不到则什么都不做,也不报错。
语法:
${表达式}
表达式:
获取请求数据
request对象存储了请求数据--->param.键名 返回值
request对象存储了请求数据--->paramvalues.键名 返回的是数组(单键多值)
通过setAttribute方法存储到作用域对象中的数据
${键名} 返回键名所对应的值。
注意:
如果存储的是普通字符串则直接返回
如果存储的是对象,则返回的是对象
获取对象中的数据:
普通对象
${键名.属性名.属性名....}
集合对象
list集合--->${键名[角标]}
map集合--->${键名.map集合存储的键名}
作用域查找顺序:
默认查找顺序:
pageConext-->request--->session--->application
注意:
每次查找都是从小到大进行查找,找到了则获取,不再继续找了。
指定查找:
${pageScope.键名}---${requestScope.键名}--${sessionScope.键名}--${applicationScope.键名}
El表达式的逻辑运算:
${逻辑表达式}:&& || !
${算术表达式}:+,-,*,/
${关系表达式}:>,<,>=,==,!=,%
特殊:
三目运算
注意:
+表示加法运算,不表示字符链接。使用EL表达式进行字符链接会报错。
EL的空值判断:
${empty 键名}
作用:
判断键名对象的值是否存有数据。
EL获取请求头数据和Cookie数据:
请求头数据:
${header}-->返回所有的请求头数据
${header["键名"]}--->返回指定的键名的请求头数据
${hedaerValues["键名"]}--->返回指定的键名(同键不同值)的值的数组。
获取Cookie数据:
${cookie}--->返回存储了所有的cookie对象的map集合
${cookie.键名}---->返回指定的cookie对象
${cookie.键名.name}--->返回指定的cookie对象存储的数据的键名。
${cookie.键名.value}--->返回指定的cookie对象存储的数据的值。
--%>
<!-- 使用传统方式获取作用域对象的数据 -->
<h3>EL表达式学习:使用传统方式获取作用域对象的数据</h3>
<b><%=request.getParameter("uname")%></b><br/>
<b><%=request.getAttribute("str")%></b><br/>
<b><%=((User)request.getAttribute("user")).getAddr().getCity()%></b><br/>
<b><%=((ArrayList)request.getAttribute("list")).get(1)%></b><br/>
<b><%=((User)((ArrayList)request.getAttribute("list2")).get(0)).getAddr().getTown()%></b><br/>
<b><%=((Map)request.getAttribute("map")).get("a")%></b><br/>
<b><%=((User)(((Map)request.getAttribute("map2")).get("a1"))).getAddr().getCity() %></b><br />
<!-- 使用EL表达式获取作用域对象数据 -->
<h3>EL表达式学习:使用EL表达式获取作用域对象数据</h3>
${param.uname}<br/>
${paramValues.fav[0]}
${str}<br/>
${user.addr.city}<br/>
${list[1]}<br/>
${list2[0].addr.town}<br/>
${map.a}<br/>
${map2.a1.addr.city}
<%
pageContext.setAttribute("hello","hello pageContext");
request.setAttribute("hello","hello request");
session.setAttribute("hello","hello session");
application.setAttribute("hello","hello application");
%>
${applicationScope.hello}--${sessionScope.hello}--${requestScope.hello}--${pageScope.hello}
<h3>EL逻辑运算</h3>
${1+2}--${"a"=="a"}--${true&&false}
${header}
jstl标签库
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%--
JSTL学习:
作用:
提高在jsp中的逻辑代码的编写效率,使用标签。
使用:
JSTL的核心标签库(重点)
JSTL的格式化标签库(讲解)
JSTL的SQL标签库(了解)
JSTL的函数标签库(了解)
JSTL的XML标签库(了解)
JSTL的核心 标签库:
1、导入jar包
2、声明jstl标签库的引入(核心标签库)
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3、内容:
基本标签:
<c:out value="数据" default="默认值"></c:out>
数据可以为常量值也可以是EL表达式。
作用:将数据输出给客户端。
<c:set var="hello" value="hello pageContext" scope="page"></c:set>
作用:存储数据到作用域对象中
var:表示存储的键名
value:表示存储的数据
scope:表示要存储的作用域对象 page request session application
<c:remove var="hello" scope="page"/>
作用:删除作用域中的指定键的数据。
var:表示要删除的键的名字
scope:表示要删除的作用域(可选)
注意:
如果在不指定作用域的情况使用该标签删除数据,会将四个作用域对象中的符合要求的数据全部删除。
逻辑标签:
<c:if test="${表达式}">
前端代码
</c:if>
作用:进行逻辑判断,相当于java代码的单分支判断。
注意:
逻辑判断标签需要依赖于EL的逻辑运算,也就是表达式中涉及到的数据必须从作用域中获取。
<c:choose>
<c:when test="">执行内容</c:when>
<c:when test="">执行内容</c:when>
...
<c:otherwise>执行内容</c:otherwise>
</c:choose>
作用:用来进行多条件的逻辑判断,类似java中的多分支语句
注意:
条件成立只会执行一次,都不成立则执行otherwise
循环标签:
<c:forEach begin="1" end="4" step="2">
循环体
</c:forEach>
作用:
循环内容进行处理
使用:
begin:声明循环开始位置
end:声明循环结束位置
step:设置步长
varStatus:声明变量记录每次循环的数据(角标,次数,是否是第一次循环,是否是最后一次循环)
注意:数据存储在作用域中,需要使用EL表达式获取。
例如:${vs.index}--${vs.count}--${vs.first}--${vs.last}
items:声明要遍历的对象。结合EL表达式获取对象
var:声明变量记录每次循环的结果。存储在作用域中,需要使用EL表达式获取。
--%>
<h3>jstl标签学习</h3>
<%--jstl基本标签--%>
<c:set var="hello" value="hello"></c:set>
<c:set var="hello" value="helloReq" scope="request"></c:set>
<c:out value="${hello}" default="null"></c:out><br/>
<c:remove var="hello" scope="page"></c:remove>
<c:out value="${requestScope.hello}"></c:out><br/>
<%--逻辑标签学习--%>
<c:if test="${a>3}">
if标签
</c:if>
<c:forEach begin="0" end="3" step="1" varStatus="vs">
</c:forEach>
<c:forEach items="${list}" var="li">
${li.name}
</c:forEach>
jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" errorPage="error.jsp" %>
<%--
Jsp的三种注释:
前端语言注释:会被转译、发送但不会被浏览器执行
java语言注释:会被转译但不会被servlet执行
jsp注释:不会转译
Jsp的page指令学习:设置jsp文件转译的各个参数
<%@ page 属性名="属性值" 属性名="属性值"...%>
language:声明jsp要被转译的语言
import:声明转译的java文件要导入的包,不同的包用逗号隔开
session:设置转译的servlet是否支持session支持,默认支持,false不支持
errorPage:设置jsp运行错误跳转的页面
...
Jsp的静态代码块:<% java代码 %>
其中的java代码会被原样转译
其中的变量均为局部变量
缺点:
在jsp代码中进行逻辑判断,书写麻烦,阅读困难
开发:
servlet进行逻辑处理,jsp进行页面展现
Jsp的全局代码块:
<%!内容%>
特点:声明的java代码转译到对应的servlet类中
注意:
全局代码块声明,局部代码块调用
Jsp脚本段语句:
特点:帮助我们快速获取变量或方法的返回值作为数据响应给浏览器
使用:<%=变量名或方法名%>
注意:变量名或方法名后不可使用分号
位置:除jsp语法要求以外的任意位置
Jsp的静态引入:<%@include file="相对路径"%>
将引入的jsp文件和当前jsp文件转译成一个java(servlet)文件
网页中显示合并后的效果
注意:静态引入的jsp文件不会单独转译
引入的jsp文件和当前文件不能出现同名变量
Jsp的动态引入: <jsp:include page="文件相对路径"></jsp:include>
特点:会将引入的jsp文件单独转译,在当前文件转译的java文件中调用引入的文件转译的java文件
注意:
引入的jsp文件和当前文件可以出现同名变量
Jsp的转发标签forwrd:
特点:同servlet
注意:标签中间出现非<jsp:param name="键名" value="值"></jsp:param>的标签均会报错
数据会以?的形式拼接在转发路径后
Jsp的九大内置对象:Jsp文件在转译成对应的servlet文件时自动生成并声明的对象,在jsp页面中直接使用即可
注意:内置对象在jsp中使用,在局部代码块或脚本段语句中使用,不能够再全局代码块中使用
内容:
pageContext:页面上下文对象,封存了其他内置对象,封存了jsp的运行信息
注意:每个jsp文件都单独拥有一个pageContext对象
request:
session
application:即就是ServletContext对象
response
out:带有缓冲区的响应对象(jsp内部使用),效率高于response
page:代表当前jsp对象,相当于this
exception:异常对象,存储了当前运行的异常信息
注意:要在page中设置isErrorPage=true开启
config:servlet中的servletConfig对象
四个作用域对象:
pageContext:当前页面,解决了在当前页面的数据共享问题,获取其他内置对象
request:一次请求
session:一次会话
application:项目内,不同用户的数据共享问题
作用:数据流转
Jsp的路径:
相对路径:文件位置不能随意更改
绝对路径(*):
jsp自带的全局路径声明:
--%>
<html>
<head>
<title>jsp基本语法学习</title>
<meta charset="UTF-8"/>
</head>
<body>
<b>jsp基本语法学习</b>
<hr />
<!--jsp静态代码块-->
<%
int a = 1;
if (a>2){
%>
<i>jsp学习</i>
<% }else{ %>
<i>jsp学废</i>
<%=str%>
<%test(); } %>
<!--jsp全局代码块-->
<%!
String str = "String1";
public String test(){
return "全局代码块";
}
%>
<!--静态引入-->
<%@include file="includeStatic.jsp"%>
<!--动态引入-->
<jsp:include page="includeActive.jsp"></jsp:include>
<!--转发标签forward-->
<%--<jsp:forward page="forward.jsp">
<jsp:param name="str" value="zsm"></jsp:param>
</jsp:forward>--%>
<!--重定向标签-->
<%--<% response.sendRedirect("a/a.jsp"); %>--%>
<!--Jsp大的内置对象学习-->
<%request.setAttribute("ss","songbin");%>
<%=request.getAttribute("ss")%>
<a href="/a/a.jsp">a.jsp</a>
</body>
</html>
Filter&Listener(过滤器和监听器)
filter:用于对指定servlet进行过滤操作(要求实现Filter接口)
web.xml配置如下:(类似servlet)
<filter>
<filter-name>my</filter-name>
<filter-class>com.manager.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>my</filter-name>
<url-pattern>/pages/main/personInfo.jsp</url-pattern>
</filter-mapping>
@WebFilter(filterName = "MyFilter")
public class MyFilter implements Filter {
public void destroy() {
System.out.println("destory");
}
//进行过滤操作的方法
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpSession session = ((HttpServletRequest)req).getSession();
if (session.getAttribute("user")==null){
System.out.println("filter1");
req.getRequestDispatcher("/Login?opo=per").forward(req,resp);
}else {
System.out.println("filter");
chain.doFilter(req, resp);//放行,让所监听的servlet工作
}
}
public void init(FilterConfig config) throws ServletException {
System.out.println("init");
}
}
Listener:用于当其所实现的接口所对应的域对象发生相对应的变化时,进行指定操作
例如:对session进行监听
实现HttpSessionListener接口
除此之外还有ServletContextListener和 HttpSessionAttributeListener接口
@WebListener()
public class MyListener implements HttpSessionListener,ServletContextListener{
// Public constructor is required by servlet spec
public MyListener() {
}
/**
* 当有新用户登录count+1
* @param se
*/
public void sessionCreated(HttpSessionEvent se) {
ServletContext sc = se.getSession().getServletContext();
int count = (int)sc.getAttribute("count");
sc.setAttribute("count",++count);
}
/**
* 当有用户退出count-1
* @param se
*/
public void sessionDestroyed(HttpSessionEvent se) {
ServletContext sc = se.getSession().getServletContext();
int count = (int)sc.getAttribute("count");
sc.setAttribute("count",--count);
}
/**
* 初始化 在线人数
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
sc.setAttribute("count",0);
}
/**
* 销毁 在线人数参数
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
ServletContext sc = sce.getServletContext();
sc.removeAttribute("count");
}
}
web.xml配置如下
<listener>
<listener-class>com.manager.listener.MyListener</listener-class>
</listener>