C/S架构和B/S是软件发展过程中出现的两种软件架构方式
特点:必须在哭独断安装特定软件
优点:图形效果显示较好
缺点:服务器升级,客户端也必须升级,不利于维护
特点:无需安装客户端,任何浏览器都可以直接访问
优点: 涉及到功能的升级,只需要升级服务器端
缺点:图形显示效果不如C/S架构
需要通过HTTP协议访问
进入tomcat安装目录bin下,双击startup.bat
打开浏览器,输入http://localhost:8080
会出现一只猫的图片,则说明启动成功
双击shutdown.bat即可关闭tomcat启动窗口
tomcat默认端口号为8080,可以通过conf/server.xml文件修改
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
注意: 修改端口号需要重新启动Tomcat才会生效
URL主要有4部分组成:协议,主机,端口,资源路径
1.tomcat控制台闪退
闪退问题是由于JAVA_HOME配置导致的,检查JAVA_HOME配置是否正确
2.404
访问资源不存在,出现404错误
3.500
服务器端出现了错误
点击file选项,选择Settings
选择Build,Execution,Deployment下的Application Servers
点击+号,选择tomcat server
选择tomcat安装目录,点击ok
项目部署tomcat
点击Add Configuration
点击+号,选择tomcat Server,选择Local
项目完成后,有时需要打成war方便部署,war包可以直接放入tomcat的webapps目录中,启动Tomcat后自动解压,即可访问
点击项目结构
然后把war包放到tomcat里面的webapps目录下启动tomcat就会自动解压,运行
如果项目有更新,就需要重新打个war包,在放入webapps目录下
servlet是运行在服务器上的应用程序。(servlet是用来处理客户端请求并产生动态网页内容的java类)
servlet:server Applet的简称,是服务器端的程序(代码,功能实现)可交互式的处理客户端发送到服务器的请求,并完成操作响应
动态网页技术
javaweb程序开发的基础,javaEE(一套接口)的一个组成部分
接收客户端的请求,完成操作
动态生成网页(页面数据可变)
将包含操作结果的动态网页响应给客户端
搭建开发环境
将servlet相关的jar包放到web目录下的WEB-INF目录下的lib文件夹下
即lib\servlet-api.jar配置到classpath中
编写servlet
实现javax.servlet.Servlet
重写5个主要方法
在核心的service方法中编写输出语句,打印访问结果
package com.blb;
import javax.servlet.*;
import java.io.IOException;
public class servlet01 implements Servlet {
/**
* 初始化方法
* 在Servlet被创建时执行。只会执行一次。
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
/**
* 获取ServletConfig对象
* ServletConfig:Servlet的配置对象
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 提供服务方法
* 每一次Servlet被访问时执行。执行多次
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello servlet");
}
/**
*
* 获取servlet的版本信息
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 销毁方法
* 在服务器正常关闭时,执行,执行一次。
*/
@Override
public void destroy() {
}
}
配置servlet
在WEB_INF下项目配置文件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>
<servlet-name>servlet01</servlet-name> <!-- 最好写成创建的类的名字-->
<servlet-class>com.blb.servlet01</servlet-class> <!-- 创建的类的路径-->
</servlet>
<servlet-mapping>
<servlet-name>servlet01</servlet-name> <!-- 必须和上面的<servlet-name>里面的一样这样才会形成映射-->
<url-pattern>/s01</url-pattern> <!-- 注意一定不要忘记加上/,不然会有错误的-->
<!-- url-pattern里面配置的内容就是浏览器地址栏输入的URL中项目名称后资源的内容-->
</servlet-mapping>
</web-app>
注意
servlet-mapping里的servlet-name一定要与servlet里的servlet-name一样
url-pattern 注意一定不要忘记加上/
url-pattern里面配置的内容就是浏览器地址栏输入的URL中项目名称后资源的内容
启动tomcat即可
1. 当服务器接受到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径
2. 查找web.xml文件,是否有对应的标签体内容。
3. 如果有,则在找到对应的全类名
4. tomcat容器会将字节码文件加载进内存,并且创建其对象,调用其方法
所以我们写的servlet,我们不需要去创建对象,也不需要调用其方法。
对象的创建,方法的调用都是由服务器来执行的。
超文本传输协议是互联网上应用最广泛的一种网络协议,是一个基于请求和响应模式的,无状态的,应用层的协议,运行与tcp协议基础之上
客户与服务器建立连接(三次握手)
客户向服务器发送请求
服务器接受请求,并根据请求返回响应的文件作为应答
客户与服务器关闭连接
当浏览器向web服务器发出请求时,它向服务器传递了一个数据块,也就是请求信息(请求报文),http请求信息由4部分组成
1.请求行 请求方法 /地址url 协议版本
2.请求头 由一些键值对组成
3 空行
4 请求正文
HTTP响应报文与HTTP请求报文相似,HTTP响应也是由4个部分组成
1.响应行
2.响应头
3.空行
4.响应正文
在servlet体系中,除了实现servlet接口,还可以通过集成GenericServlet或HttpServlet类,来完成编写
Servlet的体系结构
Servlet -- 接口
|
GenericServlet -- 抽象类
|
HttpServlet -- 抽象类
package com.blb;
import javax.servlet.*;
import java.io.IOException;
public class servlet01 extends GenericServlet {
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("hello GenericServlet ");
}
}
GenericServlet:将Servlet接口中其他的方法做了默认空实现,只将service()方法作为抽象
将来定义Servlet类时,可以继承GenericServlet,实现service()方法即可
package com.blb;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class servlet03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get方法被调用");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post方法被调用");
}
}
推荐使用继承Httpservlet
<?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>servlet01</servlet-name> <!-- 最好写成创建的类的名字-->
<servlet-class>com.blb.servlet01</servlet-class> <!-- 创建的类的路径-->
<load-on-startup>1</load-on-startup> <!-- 启动的优先级,数字越小越先起作用-->
</servlet>
<servlet-mapping>
<servlet-name>servlet01</servlet-name> <!-- 必须和上面的<servlet-name>里面的一样这样才会形成映射-->
<url-pattern>/s01</url-pattern> <!-- 注意一定不要忘记加上/,不然会有错误的-->
<!-- url-pattern里面配置的内容就是浏览器地址栏输入的URL中项目名称后资源的内容-->
</servlet-mapping>
</web-app>
url-pattern定义匹配规则,取值说明:
精确匹配 /具体的名称 只要URL路径是具体的时候才会触发Servlet
后缀匹配 *.xxx 只要是以xxx结尾的名称的时候才会触发Servlet
通配符匹配 /* 匹配所有请求,包含服务器的所有资源
通配符匹配 匹配所有请求,包含服务器的所有资源,不包括.jsp
load-on-startup
1.元素标记容器是否应该在web应用程序启动的时候就加载这个servlet
2.它的值必须是一个整数,表示servlet被加载的先后顺序
3.如果该元素的值为负数或者没有设置,则容器会当Servlet被请求时加载
4.如果值为正数或者0时,表示该容器在应用启动时就加载并初始化这个servlet,值越小,servlet的优先级越高,越优先被加载,值相同时,容器会自己选择顺序来加载
package com.blb;
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("/ser03") //同样这个斜杠也不能忘记
public class servlet03 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get方法被调用");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post方法被调用");
}
}
name:servlet名字(可选)
value: 配置url路径,可以配置多个
urlPatterns: 配置url路径,和value作用一样,不能同时和value使用
loadonstartup: 配置servlet的创建的时机,如果是0或者正数,启动程序时创建,如果是负数,则访问时创建,数值越小优先级越高
获取单个参数
request.getParameter("xxx");
获取多个参数
request.getParameterValues("xxx")
<form action="s03" method="post">
用户名:<input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="submit" value="注册">
</form>
@WebServlet("/s03")
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username=req.getParameter("username");
String password=req.getParameter("password");
System.out.println("登录账户为:"+username+"\t"+password);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String name = new String(username.getBytes("ISO8859-1"), "UTF-8");
System.out.println("用户名为:"+name);
}
由于客户端是以UTF-8字符编码将表单数据传输到服务器的,因此服务器也需要设置UTF-8字符编码进行接收
解决方法:使用从ServletRequest接口继承而来的setCharacterEncoding(charset)方法进行统一编码的设置
@WebServlet("/s04")
public class servlet03 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//设置请求参数的编码格式
req.setCharacterEncoding("UTF-8");
//获取表单提交的信息
String username = req.getParameter("username");
System.out.println("用户名"+username);
}
}
response对象用于响应客户端请求并向客户端输出信息
如果输出内容中包含中文,则出现乱码,因为服务器默认采用ISO8859-1编码响应
@WebServlet("/s04")
public class servlet03 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取输出流
PrintWriter out = resp.getWriter();
out.println("在页面打印出来");//这个是在响应的页面打印出来而不是在控制台打印
}
}
设置服务器响应的编码格式
设置客户端响应内容的头内容的文件类型及编码格式
resp.setCharacterEncoding("UTF-8");
resp.setHeader("Content-type","text/html;charset=UTF-8");
同时设置服务器的编码格式和客户端响应的文件类型及响应时的编码格式
和上面的设置效果是一样的
resp.setContentType("text/html;charset=UTF-8");
转发的作用在服务器端,将请求发送给服务器上的其他资源,以共同完成一次请求的处理
请求转发:一种在服务器内部的资源跳转方式
request.getRequestDispatcher("/目标URL-pattern").forward(request,responce)
重定向作用在客户端,客户端将请发送给服务器,服务器响应给客户端一个新的地址,客户端重新发送请求
response.sendRedirect("/目标URL-pattern")
当两个servlet需要传递参数时,选择forward转发,不建议使用sendRedirect进行传递
实例化
当用户第一次访问servlet时,由容器调用servlet的构造器创建具体的servlet对象,也可以在容器启动之后立刻创建实例,可以设置servlet是否在服务器启动时就创建
注意 只执行一次
初始化
在初始化阶段,init()方法会被调用,这个方法在javax.servlet.Servlet接口定义,其中,方法以一个servletConfig类型的对象作为参数
注意:init方法只被执行一次
服务
当客户端有一个请求时,容器就会将请求servletRequest与相应servlet对象转给servlet,以参数的形式传给service方法
此方法会被执行多次
销毁
当servlet容器停止或者重新启动都会引起销毁servlet对象并调用destroy方法
destory方法执行一次
package com.sy.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* Servlet的方法
*/
public class Demo2Servlet implements Servlet{
/**
* 初始化方法
* 在Servlet被创建时执行。只会执行一次。
*/
@Override
public void init(ServletConfig arg0) throws ServletException {
// TODO Auto-generated method stub
System.out.println("我出生了");
}
/**
* 销毁方法
* 在服务器正常关闭时,执行,执行一次。
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
System.out.println("我挂了");
}
/**
* 获取ServletConfig对象
* ServletConfig:Servlet的配置对象
*/
@Override
public ServletConfig getServletConfig() {
// TODO Auto-generated method stub
return null;
}
/**
* 获取ServletConfig对象
* ServletConfig:Servlet的配置对象
*/
@Override
public String getServletInfo() {
// TODO Auto-generated method stub
return null;
}
/**
* 提供服务方法
* 每一次Servlet被访问时执行。执行多次
*/
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws ServletException, IOException {
System.out.println("请求被响应了");
}
}
只要访问Servlet,service()就会被调用。init()只有第一次访问Servlet的时候才会被调用。destroy()只有在Tomcat关闭的时候才会被调用。
1.默认情况下,第一次被访问时,Servlet被创建
2.可以配置执行Servlet的创建时机。
在<servlet>标签下配置
(1)第一次被访问时,创建
<load-on-startup>的值为负数或不写
(2)在服务器启动时,创建
<load-on-startup>的值为正整数
HTTP协议是无状态的,不能保存每次提交的信息
如果用户发来一个新的请求,服务器无法知道它是否与上一次的请求有联系
对于那些需要多次提交数据才能完成的web项目,比如登录来说,就成问题了
将浏览器与web服务器之间多次交互当作一个整体来处理,并且将多次交互所涉及的数据(即状态)保存下来
客户端状态管理技术:将状态保存在客户端,代表性的是Cookie技术
服务器状态管理技术:将状态保存在服务器端,代表性的是Session技术(服务器传递sessionID时需要使用Cookie的方式)
package com.blb;
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;
@WebServlet("/c1")
public class cookie01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie
Cookie cookie=new Cookie("username","dyk");
Cookie cookie1=new Cookie("password","1234");
cookie.setPath("/c1");//设置cookie的路径,有效路径,当前访问资源的上一级目录,不带主机名
cookie.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒 =0 0秒 <0内存存储,默认-1浏览器关闭
cookie1.setPath("/c1");
cookie1.setMaxAge(60*60);//1小时
resp.addCookie(cookie);//添加到response对象中,响应时发送给客户端
resp.addCookie(cookie1);
}
}
内存存储,取值有三种:>0有效期,单位秒 =0 0秒 <0内存存储,默认-1浏览器关闭
package com.blb;
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;
@WebServlet("/c2")
public class cookie2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有cookie
Cookie[] cookies = req.getCookies();
//遍历cookie
if(cookies!=null)
{
for (Cookie c:cookies)
{
System.out.println(c.getName()+"\t"+c.getValue());
}
}
}
}
只要保证和cookie的名和路径一致即可修改
package com.blb;
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;
@WebServlet("/c1")
public class cookie01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//创建cookie
Cookie cookie=new Cookie("username","dyk");
Cookie cookie1=new Cookie("password","1234");
Cookie cookie2=new Cookie("username","cb");
cookie.setPath("/c1");//设置cookie的路径,有效路径,当前访问资源的上一级目录,不带主机名
cookie.setMaxAge(-1);//内存存储,取值有三种:>0有效期,单位秒 =0 0秒 <0内存存储,默认-1浏览器关闭
cookie1.setPath("/c1");
cookie1.setMaxAge(60*60);
resp.addCookie(cookie);//添加到response对象中,响应时发送给客户端
resp.addCookie(cookie1);
resp.addCookie(cookie2);
}
}
cookie和cookie2会当作两个cookie存储
如果改变cookie的name和有效路径会新建cookie,而改变cookie的值,有效期会覆盖原有的cookie
cookie默认不支持中文,只能包含ASCII字符,所以cookie需要对Unicode字符进行编码,否则会出现乱码
编码可以使用java.net.URLEncoder类的encode(String str,String encoding)方法
解码使用java.net.URLDecoder类的decode(String str,String encoding方法
package com.blb;
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;
import java.net.URLEncoder;
@WebServlet("/c1")
public class cookie01 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cookie cookie=new Cookie(
URLEncoder.encode("姓名","UTF-8"),
URLEncoder.encode("邓远科","UTF-8")
);
resp.addCookie(cookie);
}
}
package com.blb;
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;
import java.net.URLDecoder;
@WebServlet("/c2")
public class cookie2 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取所有cookie
Cookie[] cookies = req.getCookies();
//遍历cookie
if(cookies!=null)
{
for (Cookie c:cookies)
{
System.out.println(URLDecoder.decode(c.getName(),"UTF-8") +"\t"+ URLDecoder.decode(c.getValue(),"UTF-8"));
}
}
}
}
session是服务器自动创建的,通过request对象获取
HttpSession session = request.getSession();
setAttribute(属性名.Object)保存数据到session
session.setAttribute("username","dyk");//以键值对形式存储在session作用域中
getAttribute(属性名) 获取session中数据
session.getAttribute("username");//通过String类型的key访问Object类型的value
removeAttribute(属性名)从session中删除数据
session.removeAttribute("username");//通过键移除session作用域中的值
request是一次请求有效,请求改变,则request改变
session是一次会话有效,浏览器改变,则session改变
开始 : 第一次使用Session的请求产生,则创建Session
结束
浏览器关闭,则失效
Session超时,则关闭
session.setMaxInactiveInterval(Seconds);//设置最大有效时间 单位 秒
手工销毁,则失效
session.invalidate(); //登陆退出,注销
session失效
session.setMaxInactiveInterval(60*60); //设置session最大有效期为1小时
session.invalidate(); //手工销毁
HttpSession session = req.getSession();
//重写url追加sessionid
String newurl = resp.encodeRedirectURL("/目标URL-pattern");
resp.sendRedirect(newurl);
页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username" /><br>
密码:<input type="password" name="password" /><br>
验证码:<input type="text" name="vcode" /><img src="/servlet01_war_exploded/createcode"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
生成验证码
package com.blb.demo;
import cn.dsna.util.images.ValidateCode;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/createcode")
public class CreateCode extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ValidateCode vc=new ValidateCode(100,50,4,10);
//获得生成验证码里的内容
String code = vc.getCode();
HttpSession session = request.getSession();
session.setAttribute("code",code);
//响应给客户端
vc.write(response.getOutputStream());
}
}
package com.blb.demo;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.Provider;
@WebServlet("/login")
public class servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
String username="dyk";
String password="123";
String username1 = req.getParameter("username");
String password1 = req.getParameter("password");
String vcode = req.getParameter("vcode");
HttpSession session = req.getSession();
String code = (String)session.getAttribute("code");
if(!vcode.isEmpty()&&code.equalsIgnoreCase(vcode)){
if(username.equals(username1)&&password.equals(password1)){
PrintWriter writer = resp.getWriter();
writer.println("登录成功");
}
else{
PrintWriter writer = resp.getWriter();
writer.println("登录失败,账号或密码错误");
}
}
else{
PrintWriter writer = resp.getWriter();
writer.println("验证码错误");
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
全局对象,也拥有作用域,对应一个Tomcat中的web应用
当web服务器开启时,会为每一个web应用创建一块共享的存储区域
ServletContext在eb服务器启动时创建,服务器关闭时销毁
获取当前项目在服务器发布的真实路径
String realPath = servletContext.getRealPath("/");
// D:\idea\maven01\servlet01\out\artifacts\servlet01_war_exploded\
获取项目的上下文路径,应用程序名
String contextPath = servletContext.getContextPath();
System.out.println(contextPath);
System.out.println(request.getContextPath());
// /servlet01_war_exploded
过滤器是处于客户端与服务器目标资源之间的一道过滤技术
执行地位在servlet之前,客户端发送请求时,会先经过Filter,在到达目标Servlet中,响应时,会根据执行流程再次反向执Filter
可以解决多个servlet共性代码的冗余问题(例如乱码处理,登录验证)
servlet API 中提供了Filter接口,开发人员编写一个java类实现了这个接口,这个java类称之为过滤器
编写java类实现Filter接口,重写3个方法
在doFilter中编写拦截逻辑
设置拦截路径
package com.blb.demo;
import javax.servlet.*;
import java.io.IOException;
public class filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化了");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("过滤前");
filterChain.doFilter(servletRequest,servletResponse);
System.out.println("过滤后");
}
@Override
public void destroy() {
System.out.println("过滤器销毁了");
}
}
和servlet一样都可以通过注解和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">
<filter>
<filter-name>filter</filter-name>
<filter-class>com.blb.demo.filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*
@WebFilter("value=/过滤目标资源")
过滤器路径通常有三种形式
精确过滤匹配,/xxx.xxx ;例如index.jsp
后缀过滤匹配 比如*.jsp ,*.html
通配符过滤 /*,表示拦截所有,注意过滤器不能使用/匹配
在一个Web应用中,可以编写多个filter,这些filter组合起来称之为Filter链,
优先级
如果为注解的话,是按照类全名称的字符串顺序决定顺序
如果web.xml按照filter-mapping注册顺序,从上往下
web.xml配置高于注解方式
如果web.xml和注解同时配置,会创建多个过滤器对象,造成多次过滤,因此建议只用注解
过滤器解决编码问题
package com.blb.demo;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class filter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化了");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//统一处理和响应的乱码
servletRequest.setCharacterEncoding("utf-8");
servletResponse.setContentType("text/html;charset=utf-8");
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("过滤器销毁了");
}
}
如果需要用到session那么必须向下转型
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request= (HttpServletRequest)servletRequest;
HttpServletResponse response=(HttpServletResponse)servletResponse;
HttpSession session = request.getSession();
filterChain.doFilter(servletRequest,servletResponse);
}