servlet
-
什么是servlet?
Servlet 是javaweb开发的基石,与平台无关的服务器组件,它是运行在Servlet容器/Web应用服务器/Tomcat,负责客户端进行通信
Servlet的功能:
1、创建并返回基于客户请求的动态HTML页面。
2、与数据库进行通信
- 如何使用Servlet?
Servlet本身是一组接口,自定义一个类,并且实现servlet接口,这个类就具备了接受客户端请求以及做出响应的功能。
浏览器不能直接访问Servlet文件,只能通过映射的方式来间接访问servlet,映射需要开发者手动配置,有两种配置方式。
- 基于xml文件的配置方式
<sevlet>
<servlet-name>hello</servlet-name>
<servlet-class>servlet路径</servlet-class>
</sevlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/demo2</url-pattern>
</servlet-mapping>
- 基于注解
@webServlet("/demo2")
public class HelloServlet implements Servlet{
}
Servlet 的生命周期
1、当浏览器访问Servlet的时候,Tomcat会查询当前servlet的实例化对象是否存在,如果不存在,则通过反射机制动态创建对象,如果存在,就直接执行第3步。
2、调用init方法完成初始化操作。
3、调用service方法完成业务逻辑操作。
4、关闭Tomcat时,会调用destory方法,释放当前对象所占用的资源。
servlet 的生命周期方法:无参构造函数、init、service、destory
1、无参构造函数只调用一次,创建对象。
2、init只调用一次,初始化对象。
3、service调用多次,执行业务方法。
4、destory只调用一次,卸载对象。
ServletConfig
该接口时用来描述Servlet的基本信息
getServletName() 返回 Servlet的名称,全类名(带着包名的全类名)
getInitParameter(String key) 获取init参数的值(web.xml)
getInitParameterNames() 返回所有的initParameter的name值,一般用作遍历初始化参数
getServletContext() 返回ServletContext对象,它是Servlet的上下文,整个Servlet的管理者
ServletConfig 和 ServletContext的区别:
ServletConfig作用于某个Servlet实例,每个Servlet都有对应的ServletConfig,ServletContext作用于整个web应用,一个web应用对应一个ServletContext,多个Servlet实例对应一个ServletContext。
一个是局部对象,一个是全局对象。
Servlet的层次结构
Servlet--->GenericServlet--->HttpServlet
Http请求又很多类型,常用得有四种:
GET读取
POST保存
PUT修改
DELETE删除
GenericServlet实现Servlet接口,同时为它得子类屏蔽了不常用的方法,字类只需要重写service方法即可。
HTTPServlet继承GenericServlet,根据请求类型进行分发处理,Get进去doGet方法,Post进入doPOST方法。
开发者自定义的servlet类只需要继承HttpServlet即可,重新doGet和doPost
package com.jlu.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Get");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("post");
}
}
jsp
jsp本质上就是servlet,jsp主要是负责与用户交互,将最终的界面呈现给用户,HTML+JS+CSS+JAVA的混合文件。
当服务器接收到一个后缀是jsp的请求时,将该请求交给jsp引擎处理,每一个jsp页面第一次被访问的时候,jsp引擎会将它翻译成一个Servlet文件,再由web容器调用Servlet完成响应。
单纯从开发的角度看,jsp就是在HTML中嵌入java程序。
具体嵌入的方式有3种:
1、jsp脚本,执行java逻辑代码
<% java 代码 %>
2、jsp声明:定义java方法
<%!
声明 java 方法
%>
3、jsp表达式:把java对象直接输入出到HTML页面中
<%= java变量 %>
<%!
public String test(){
return "Hello world";
}
%>
<%
String str = test();
%>
<%=str%>
实例:
<%
List<String> names = new ArrayList<>();
names.add("张三");
names.add("李四");
names.add("王五");
List<Integer> age = new ArrayList<>();
age.add(21);
age.add(22);
age.add(23);
%>
<table>
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<%
for (int i= 0;i<names.size();i++){
%>
<tr>
<td>
<%=names.get(i) %>
</td>
<td>
<%=age.get(i) %>
</td>
</tr>
<%
}
%>
</table>
运行结果
[图片上传失败...(image-70e518-1595999863396)]
浏览器当中的源码:
<html>
<head>
<title>$Title$</title>
</head>
<body>
<table>
<tr>
<th>姓名</th>
<th>年龄</th>
</tr>
<tr>
<td>
张三
</td>
<td>
21
</td>
</tr>
<tr>
<td>
李四
</td>
<td>
22
</td>
</tr>
<tr>
<td>
王五
</td>
<td>
23
</td>
</tr>
</table>
</body>
</html>
jsp的内置对象9个
request : 表示一次请求,HttpServletRequest.
respond : 表示一次响应,HttpServletResponse。
pageContext :页面上下文,获取页面信息,pageContext。
session :表示一次会话,保存用户信息,httpsession.
application :表示当前web应用,全局对象,保存所有用户共享信息,ServletContext。
config :当前jsp对应的Servlet 的ServletConfig对象,获取当前Servlet信息。
out :向浏览器输出数据,jspWriter。
page :当前jsp对应的Servlet对象,Servlet。
excerption :表示jsp页面当前发生的异常,Exception。
常用的是 request 、 response、session、application、pageContext
requst 常用方法:
1、String getParameter(String key) 获取客户端传来的的数据
2、void setAttribute(String key,Object value) 通过键值对的形式保存数据。
3、Object getAttribute(String key) 通过key 取出 value。
4、RequestDispatcher getRequestDispatcher(String path) 返回一个RequestDispatcher 对象,该对象的forward 方法用于请求转发。
5、String[] getparameterValues() 获取客户端传来的多个同名参数。
6、void setCharacterEncoding(String charset) 中文乱码时可以指定每一个请求的编码。
以下为实例:
//这个是实现jsp间转发功能的
<h1>test</h1>
<%
String idstr = request.getParameter("id");//取出数据,这是String类型的
Integer id = Integer.parseInt(idstr);//把idstr转成int类型
id++;
//将数据存入request中
request.setAttribute("number",id);
//将请求转发给test2.jsp
request.getRequestDispatcher("test2.jsp").forward(request,response);//还要把请求和响应传过去
%>
<h1>test2</h1>
<%
Integer number = (Integer)request.getAttribute("number");//取出value值并且转化为Integer类型
%>
<%=number%>
<%
String[] names = request.getParameterValues("name");//这是传入多组values时,使用数组
%>
<%=Arrays.toString(names)%>
运行图:
[图片上传失败...(image-2ae4d-1595999863397)]
HTTP请求状态码
200:正常
404:资源找不到
400:请求类型不匹配
500:java程序抛出异常
response 常用方法:
1、sendRedirect(String path) 重定向,页面之间的跳转。
转发 getRequestDispatcher 和重定向 sendRedirect的区别:
转发是将同一个请求传给下一个页面,重定向是创建一个新的请求传给下一个页面,之前的请求结束生命周期。
转发:同一个请求在服务器之间传递,地址栏不变,也叫服务器跳转。
重定向:由客户端发送一次新的请求来访问跳转后的目标资源,地址栏改变,也叫客户端跳转。
如果两个页面之间需要通过request来传值,则必须要转发,不能使用重定向。
用户登陆,如果用户名和密码正确,则跳转到首页(转发),并展示用户名,否则重新回到登陆界面(重定向)。
Session
用户会话
服务器无法识别每一次HTTP请求的出处(不知道来自于哪一个客户端),它只会接受到一个请求信号,所以就存在一个问题:将用户的响应发送给其他人,必须有一种技术让服务器知道请求来自哪里,这就是会话技术。
会话:就是客户端和服务器之间发生的一系列连续的请求和响应的过程,打开浏览器进行操作到关闭浏览器的过程。
会话状态:指服务器和浏览器在会话过程中产生的状态信息,借助于会话状态,服务器能够把属于同一次会话的一系列请求和响应关联起来。
实现会话有两种方式:
- session
- cookie
属于同一次会话的请求都有一个相同的标识符,sessionID
session常用方法:
String getId() 获取sessionID
void setMaxIactiveInterval(int interval) 设置session的失效时间,单位为秒。
int getMaxIactiveInterval() 获取当前session的失效时间
void invadate() 设置session立即失效
void setAttribute(String key ,Object value) 通过键值对的形式来储存数据
Object getAttribute(String key) 通过键获取对应的数据
void removeAttribute(String key) 通过键删除对应的数据
Cookie
Cookie是服务端在HTTP响应中附带传给浏览器的一个小文本文件,一旦浏览器保存在某个cookie,在之后的请求和响应过程中,会将此cookie来回传递,这样就可以通过Cookie这个载体完成客户端和服务端的数据交互。
Cookie
- 创建Cookie
Cookie cookie = new Cookie("name","tom");
response.addCookie(cookie);
- 读取Cookie
Cookie[] cookies = request.getCookie();
for(Cookie cookie:Cookies){
out.write(cookie.getName()+":"+cookie.getValue()+"<br/>");
}
Cookie常用的方法
void setMaxAge(int age) 设置Cookie的有效时间,单位为秒
int getMaxAge() 获取Cookie的有效时间
String getName() 获取cookie的name
String getValue() 获取Cookie的Value
session 和Cookie的区别
session: 保存在服务器
保存的数据是Object
会随着会话的结束而销毁
保存重要信息
Cookie:保存在浏览器
保存的数据是String类型
可以长期保存在浏览器中,与会话无关
保存不重要数据
存储用户信息:
session:setAttribute("name","admit") 存
getAttribute("name") 取
生命周期:服务端:只要web应用重启就销毁,客户端:只要浏览器关闭就销毁。
退出登录:session.invalidate()
Cookie :response.addCookie(new Cookie(name,"admit")) 存
生命周期:不随服务端的重启而销毁,客户端:默认是只要关闭浏览器就销毁,我们通过setMaxAge()方法设置有效期,一旦设置了有效期,则不随浏览器的关闭而销毁,而是由设置的时间来决定。
退出登录:setMaxAge(0)
jsp内置对象作用域
4个
page、 request、session、application
setAttribute、getAttribute
page作用域:对应的内置对象是pageContext
request作用域:对应的内置对象是 request
session 作用域: 对应的内置对象session
application作用域: 对应的内置对象是application
page< request< session < application
page 只在当前页面有效
request 在一次请求内有效
session 在一次会话内有效
application 对应整个web应用的
EL表达式
Expression Language表达式语言,替代jsp页面中数据访问时的复杂编码,可以非常便捷地去取域对象(pageContext、request、session、application)中报存的数据,提前时一定要先setAttribute,EL就相当于在简化getAttritube
${变量名} 变量名就是setAttritube 对应的 key 值。
1、EL对于4种域对象的默认查找顺序:
pageContext —> request —> session —> application
按照上述的顺序进行查找,找到立即返回,在application 中也无法找到,则返回 null
2、指定作用域进行查找
pageContext :${pageScope.name}
request : ${requestScope.name}
session :${sessionScope.name}
application : ${applicationScope.name}
JSTL
jsp Standard Tag Library JSP 标准标签库,jsp为开发者提供的一系列的标签,使用这些标签可以完成一些逻辑处理,比如循环遍历集合,让代码更加简介,不在出现jsp脚本穿插的情况。
实际开发中EL 和 JSTL结合起来使用,jstl侧重于逻辑处理,EL负责展示数据
jstl 的使用
1、需要导入 jar 包 存放的位置 web / WEB-INF
2、在jsp页面开始的地方导入jstl标签库
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
3、在需要使用的地方使用
<c:forEach items="${list}" var="user">
<tr>
<td>${user.age}</td>
<td>${user.name}</td>
<td>${user.score}</td>
<td>${user.address}</td>
</tr>
</c:forEach>
JSTL 优点:
1、提供了同意的标签
2、可以用于编写各种动态功能
- 核心常用标签:
set 、out 、 remove 、 catch
set :向域对象中添加数据
<%
request.setAttritube(key,value);
%>
<c:set var="name" value="tom"></c:set>
${name}<%--存在pages当中--%>
out : 输出域对象中的数据
<c:set var ="name" value="tom"></c:set>
<c:out value ="${name}"></c:out> 第一种输出
${name} 第二种输出
区别:
当没有set的时候,${name} 显示的为空,在客户端上空白,但用标签<c:out value = "${name}" default= "未定义"></c:out>
可以设置他的默认显示值出来,这样客户可以知道什么回事。
remove :删除域对象中的数据
<c:out value="${name}"></c:out>
<c:remove var="name" scope="page"></c:remove> 删除操作
<hr>
<c:out value ="${name}" default="未定义"></c:out>
catch :捕获异常信息
<c:catch var="error">
<%
int a = 100/0 ;
%>
</c:catch>
${error}
未定义 java.lang.ArithmeticException: / by zero
- 条件标签 :if choose
<c:set var="num1" value="1"></c:set>
<c:set var="num2" value="2"></c:set>
<c:if test="${num>num2}">ok</c:if>
<c:if test="${num1<num2}">fail</c:if>
<hr>
<c:choose>
<c:when test="${num2>num1}">ook</c:when>
<c:otherwise>fail</c:otherwise>
</c:choose>
- 迭代标签 :forEach
<%
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
list.add("f");
list.add("g");
request.setAttribute("list",list);
%>
<c:forEach items="${list}" var="str" begin="2" end="4" step="2" varStatus="sta">
${sta.count}、${str}
</c:forEach>
格式化标签库常用标签
<%
request.setAttribute("date",new Date());
%>
${date}
<hr>
<fmt:formatDate value="${date}" pattern="yyyy-MM-dd HH:mm:ss"></fmt:formatDate>
<fmt:formatNumber value="123.2586" maxFractionDigits="2" maxIntegerDigits="3"></fmt:formatNumber>
函数标签库常用标签
<%
request.setAttribute("info","java,cpp,python");
%>
${fn:contains(info, "python")}<br><%-- 判断字符串中是否存在此字符--%>
${fn:startsWith(info, "java")}<br> <%--判断是否从Java开始--%>
${fn:endsWith(info, "cpp")}<br> <%--判断是否以cpp结尾--%>
${fn:indexOf(info, "va")}<br>
${fn:substring(info, 2,3 )} <br>
${fn:split(info, ",")[0]}-${fn:split(info, ",")[1]}
过滤器
Filter
功能:
- 用来拦截传入的请求和传出的响应
- 修改活以某种方式处理正在客户端和服务端之间交换的数据流
如何使用?
与Servlet类似,Filter 是Java WEB提供的一个接口,开发者只需要自定义一个类似并且实现该接口即可。
public class CharacterFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
filterChain.doFilter(servletRequest,servletResponse);//类似重定向
}
@Override
public void destroy() {
}
}
web.xml
<filter>
<filter-name>Charcater</filter-name>
<filter-class>com.JLUZH.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Charcater</filter-name>
<url-pattern>/test</url-pattern>
<url-pattern>/login</url-pattern>
</filter-mapping>
注意:doFilter 方法种处理完业务逻辑之后,必须添加 filterChain.doFilter(servletRequest,servletResponse); 否则 请求/响应无法向后传递,一直停留在过滤器中。
Filter 的生命周期
当Tomcat 启动时,通过反射机制调用Filter 的无参构造函数创建实例化对象,同时调用 init 方法实现初始化,doFilter 方法调用多次,当Tomcat 服务关闭时,调用 destory 来销毁 Filter 对象。
无参构造函数:只调用一次,当Tomca 启动时调用(Filter 一定要进行配置)
init方法:只调用一次,当 Filter 的实例化对象创建完成之后调用
doFilter :调用多次,访问Filter 的业务逻辑都写在 Filter 中
destory :只调用一次,Tomcat 关闭时调用。
同时配置多个Filter ,Filter 的调用顺序是由 web.xml 中的配置顺序决定的,写在上面的配置先调用,因为web.xml 是从上到下的顺序读取的。
也可以通过注解的方式来简化web.xml 中的配置
filter>
<filter-name>Charcater</filter-name>
<filter-class>com.JLUZH.filter.CharacterFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Charcater</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
等于
@WebFilter("/test")
public class CharacterFilter implements Filter {
}
实际开发中 Filter 的使用场景:
1、统一处理中文乱码。
2、屏蔽敏感词。
@WebFilter("/test")
public class WordFilter implements Filter {
//将”敏感词“ 替换成 ***
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletRequest.setCharacterEncoding("UTF-8");
String value = servletRequest.getParameter("value");
value= value.replaceAll("敏感词","***");//这里替换之后需要用setAttritube方法来重新存vaule
servletRequest.setAttribute("value",value);//否则结果是没替换成功
filterChain.doFilter(servletRequest,servletResponse);
}
}
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String value= (String) req.getAttribute("value");//还是用getAttritube 来取
System.out.println("Servlet"+value);
}
}
3、控制资源的访问(如:下载资源前需要登陆)
以下案例用session判断是否登陆,未登陆则跳转login页面,登陆了就download页面
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@WebFilter("/download.jsp")
public class downFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//Filter中没有getsession方法,所以就转为HttpServlet
HttpServletRequest request = (HttpServletRequest) servletRequest;//子类
HttpServletResponse response =(HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
String name=(String) session.getAttribute("name");
if (name==null){
//未登陆
response.sendRedirect("/login.jsp");
}else{
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
文件上传下载
- 上传:
待复习
- 下载
//设置响应方式
resp.setContentType("application/x-msdownload");//启用下载方式
//设置下载之后的文件名
resp.setHeader("Content-Disposition","attachment;filename="+fileName);
//上面的都死写死的
OutputStream outputStream = resp.getOutputStream();
String path = req.getServletContext().getRealPath("file/"+fileName);
InputStream inputStream = new FileInputStream(path);
int temp =0;
while((temp=inputStream.read())!=-1){
outputStream.write(temp);
}//用字节流读,大多数类型文件都可以
inputStream.close();
outputStream.close();
Ajax
Asynchronous JavaScript And Xml
Ajax 不是新的的编程语言,指的是一种交互方式,异步加载,客户端和服务器的数据交互更新在局部页面的技术,不需要刷新整一个页面(局部刷新)
优点:
1、局部刷新,效率更高
2、用户体验好
基于JQuery的Ajax
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<script type="text/javascript" src="js/jquery-3.5.1.min.js"></script>
<script type="text/javascript">
$(function () {
var btn = $("#btn");
btn.click(function () {
$.ajax({
url:'/test',
type:'post',
data:'id=1',
dataType:'text',
success :function (data) {
var text = $("#text");
text.before("<span>"+data+"</span><br>")
}
});
})
})
</script>
</head>
<body>
<input id="text" type="text"><br>
<input id="btn" type="submit" value="提交">
</body>
</html>
不能用表单提交请求,改用jQuery方式动态绑定事件来提交。
Servlet 不能跳转到jsp ,只能将数据返回
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/test")
public class TestServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String id = req.getParameter("id");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
String str = "hello world";
resp.getWriter().write(str)
// req.setAttribute("str",str);
// req.getRequestDispatcher("test.jsp").forward(req,resp);//这里不能跳转,不然就会显示多一个输入框和提交按钮
}
}
传统的WEB 数据交互 VS AJAX数据交互
- 客户端请求的方式不同:
传统,浏览器发送同步请求(form ,a)
AJAX,异步引擎对象发送异步请求
- 服务器响应的方式不同
传统,响应一个完整jsp页面(视图)
AJAX,响应需要的数据
- 客户端处理的方式不同:
传统:需要等待服务器完成响应并且重新加载整个页面之后,用户才能进行后后续的操作
AJAX:动态更新页面中局部内容,不影响用户的其他操作
AJAX原理
[图片上传失败...(image-c9b35f-1595999863397)]