3.Filter
过滤器。
3.1.filter的功能
1.可以设置拦截或者放行(验证,是否登录,info页面仅登录可用)
2.可以在请求到达servlet之前修改request对象,也可以在响应之后修改response对象(字符编码格式)
3.2.如何编写Filter
1.编写一个类实现javax.servlet.Filter接口
2.注册该filter(先在web.xml中根据提示完成)
3.3.Filter的生命周期
1.Init:随着应用的启动而实例化
2.doFilter:每访问一次filter,就会执行该方法一次
3.Destroy:应用的卸载或者服务器关闭
3.4.Servlet和filter如何关联在一起
最简单的方式就是通过url-pattern。servlet和filter设置相同的url-pattern。
为什么没有报错?
不是说url-pattern不可以设置相同的嘛?为什么filter和servlet设置同一个url-pattern不会报错?
不可以设置相同的url-pattern是因为针对的是servlet。servlet从功能上来说,是开发动态web资源,做出响应的,如果多个servlet配置了相同url-pattern,究竟应该选择哪个来执行呢?
但是filter功能上来说,和servlet完全不同,filter定位拦截、过滤,而不是做出响应。
更多的是功能上的一个差异。功能上的一个定义。
3.4.1.filter和servlet设置相同url-pattern,servlet代码不执行
为什么呢?
filter默认执行的是拦截操作,如果想要放行代码往下执行,必须要有这句话
此时filter和servlet的代码均会被执行到。
3.4.2.filter可以设置/*吗?
可以的。不会存在servlet的那些诸多烦恼。但是filter一般不会设置/。
设置了/*之后所有的servlet都不会出现中文乱码了。
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">
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
FilterDemo:
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author shihao
* @create 2020-07-01 9:44
*/
//@WebFilter
public class FilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletResponse.setContentType("text/html;charset=utf-8");
System.out.println("doFilter");
//让filter放行servlet的代码
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
FirstServlet:
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;
/**
* @author shihao
* @create 2020-07-01 10:05
*/
@WebServlet("/servlet")
public class filterServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet");
}
}
SecondServlet:
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("/servlet2")
public class SecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet2");
response.getWriter().println("您好servlet");
}
}
3.5.filter链
在一个请求的处理中,可以设置多个filter,然后会形成一个链,依次执行。
可以设置多个filter,多个filter如果url-pattern相同,也不会有任何问题。因为filter是一个过滤器或者说拦截器,而不是像servlet一样,是一个做出响应的组件,所以不会有任何问题。
那么,接下来有一个问题?
如果多个filter同时参与到一个请求的处理中,那么先调用哪个filter呢?
1.对于在web.xml中声明的filter,满足如下规律:
首先看能够处理当前请求的filter有哪些,其次再看
mapping声明的先后顺序,就是最终的调用顺序。所以看上面的web.xml,会先调用firstServlet再调用secondServlet。
2.对于注解的方式,顺序是类名首字母的ASCII先后顺序。
AFilter SFilter,先A后S
3.6.整个请求的处理流程
比如一个叫做ROOT的应用,里面配置servlet,url-pattern叫做/servlet,同时配置了两个filter,一个AFilter叫做/*,一个BFilter叫做/servlet。都是采用注解的方式。
当访问如下请求时
http://localhost:8080/servlet2
执行流程如下:
1.浏览器地址栏输入如下地址,构建一个请求报文
2.请求报文传输到指定机器的指定端口8080端口
3.被connector接收到,然后将其转成request对象,同时生成一个response对象
4.这两个对象被传给engine,engine挑选host来处理该请求
5.将这两个对象传给选好的host,host选择合适的Context来处理
6.这两个对象传给Context,请求的资源/servlet,Context根据请求的资源在当前应用下寻找合适的组件来处理该请求
7.首先先查找filter,哪些filter可以处理(匹配)该请求,将这两个filter按照一定的顺序组成一个链表
8.接下来去查找servlet,匹配到对应的servlet,然后将servlet添加到filter的链后面
9.接下来依次调用链上的组件,然后将request和response依次传进去,先执行filter接下来执行servlet,然后执行完毕,返回
10.connector读取reponse里面的数据生成响应报文
类比转发包含
3.6.1.filter链的执行顺序
控制台输出:
执行流程:
访问:http://localhost:8080/servlet2
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">
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>FilterDemo</filter-class>
</filter>
<filter-mapping>
<filter-name>secondFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>secondFilter</filter-name>
<filter-class>FilterDemo2</filter-class>
</filter>
</web-app>
filterServlet2 :
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("/servlet2")
public class filterServlet2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("servlet2");
response.getWriter().println("您好servlet");
}
}
FilterDemo :
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* @author shihao
* @create 2020-07-01 9:44
*/
//@WebFilter
public class FilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
servletResponse.setContentType("text/html;charset=utf-8");
System.out.println("doFilter before");
//让filter放行servlet的代码
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("doFilter after");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
FilterDemo 2:
import javax.servlet.*;
import java.io.IOException;
public class FilterDemo2 implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init2");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter2 before");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("doFilter2 after");
}
@Override
public void destroy() {
System.out.println("destroy2");
}
}
3.7.Login2 功能
1.设置编码格式
2.拦截放行
登录页面
Info.jsp
要求有登录才可以访问。
有的页面需要验证权限info.jsp,有的页面不需要验证权限login.jsp。
建议大家课后自己去画一个流程图
1.当前访问的资源应该用哪个API?
getRequestURI /app/login
getRequestURL http://localhost:8080/app/login
getServletPath /login
getContextPath /app
2.放行对应的是哪句代码?filterChain.doFilter(request,response)
globalFilter :
package com.cskaoyan;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author shihao
* @create 2020-07-01 14:22
*/
@WebFilter("/*")
public class globalFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//强转
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
//中文乱码
req.setCharacterEncoding("utf-8");
resp.setContentType("text/html;charset=utf-8");
//info.jsp进行权限验证,如果登录,则可以该页面,如果没有登录,直接定位到登录页面
String servletPath = request.getServletPath();
if (auth(servletPath)) {
//需要权限验证
String username = (String) request.getSession().getAttribute("username");
if (username == null) {
//没有登陆,拦截
response.sendRedirect(request.getContextPath() + "/login.jsp");
//response.setHeader("refresh","2;url=" + request.getContextPath() + "/login.jsp");
return;
}
}
//不需要进行权限验证
chain.doFilter(req, resp);
}
/**
* 哪些访问路径需要权限验证
* @param servletPath
* @return
*/
private boolean auth(String servletPath) {
if ("/info.jsp".equals(servletPath)){
return true;
}
return false;
}
public void init(FilterConfig config) throws ServletException {
}
}
1.JSON
需要记住一点:{}表示的是一个对象,[]表示的是一个数组或者集合。
两者之间都可以正常执行,没有报错,他们之间的区别是什么呢?
上面的严格来说才表示的是json对象,下面表示的json字符串。
java端服务端产生的数据如果要和前端进行通讯,那么采用的就是json字符串来进行 通讯。
1.1.java语言如何操作json
前后端分离的概念。页面和数据分别来自于两个不同的系统。
比如一个项目:页面内来自于localhost:8080,数据来自于localhost:8084,
java语言提供对应页面所需要的数据。
数据返回就是以json字符串的形式来返回。
1.1.1.java对象如何转成json字符串
{“name”:“zhangsan”, “age”: 24}
可以用一个网站来校验besjon.com
专门用来校验json字符串。
mainTest :
/**
* @author shihao
* @create 2020-07-01 22:05
*/
public class mainTest {
public static void main(String[] args) {
Person person = new Person();
person.setName("zhangsan");
person.setAge(24);
//需要把person对象转成json字符串
//var person = {"name": "zhangsan", "age": 24}
String perStr = "{\"name\": " + "\"" + person.getName() + "\"" + ", \"age\": " + person.getAge() + "}";
System.out.println(perStr);
}
}
使用工具类来完成这些操作。
Gson google json解析工具
Fastjson alibaba
Jackson SpringMVC框架内置
不管怎么样,完成的功能都是一样的。
mainTest2 :
import com.google.gson.Gson;
/**
* @author shihao
* @create 2020-07-01 22:09
*/
public class mainTest2 {
public static void main(String[] args) {
Person person = new Person();
person.setName("zhangsan");
person.setAge(24);
//将java对象转换成json对象
Gson gson = new Gson();
String s = gson.toJson(person);
System.out.println(s);
}
}
将数组或者集合转成json字符串呢?
mainTest2 :
```java
import com.google.gson.Gson;
import java.util.ArrayList;
import java.util.List;
/**
* @author shihao
* @create 2020-07-01 22:09
*/
public class mainTest2 {
public static void main(String[] args) {
Person person = new Person();
person.setName("zhangsan");
person.setAge(24);
//将java对象转换成json对象
Gson gson = new Gson();
String s = gson.toJson(person);
System.out.println(s);
Person person2 = new Person();
person2.setName("lisi");
person2.setAge(22);
List<Person> people = new ArrayList<>();
people.add(person);
people.add(person2);
String s1 = gson.toJson(people);
System.out.println(s1);
}
}
1.1.2.json字符串如何转成java对象
mainTest3 :
```java
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import jdk.nashorn.internal.runtime.arrays.ArrayIndex;
import java.util.ArrayList;
import java.util.List;
/**
* @author shihao
* @create 2020-07-01 22:25
*/
public class mainTest3 {
public static void main(String[] args) {
//如果被parse的对象是[],用Array
//如果被parse的对象是{},用Object
//{"name":"zhangsan","age":24}
//[{"name":"zhangsan","age":24},{"name":"lisi","age":22}]
String person = "{\"name\":\"zhangsan\",\"age\":24}";
String people = "[{\"name\":\"zhangsan\",\"age\":24},{\"name\":\"lisi\",\"age\":22}]";
//将json字符串转成对应的java类型
Gson gson = new Gson();
Person person1 = gson.fromJson(person, Person.class);
//如何将一个数组对象的数据转成List对象的java数据类型
//1.
JsonElement jsonElement = new JsonParser().parse(people);
//根据json字符串最外侧是[]还是{}灵活的去选择getAsJsonArray还是getAsJsonObject
JsonArray jsonArray = jsonElement.getAsJsonArray();
List<Person> list = new ArrayList();
for (JsonElement p : jsonArray) {
Person person2 = gson.fromJson(p, Person.class);
list.add(person2);
}
System.out.println(list);
}
}