java 端口转发 过滤,Java 过滤器(Filter)

一、什么是过滤器

过滤器是Servlet的高级特性之一,是实现Filter接口的Java类!

过滤器的执行流程:

a8c73d1bbd8a

从上面的图我们可以发现,当浏览器发送请求给服务器的时候,先执行过滤器,然后才访问Web的资源。服务器响应Response,从Web资源抵达浏览器之前,也会途径过滤器。

过滤器的用途:过滤一些敏感的字符串【规定不能出现敏感字符串】、避免中文乱码【规定Web资源都使用UTF-8编码】、权限验证【规定只有带Session或Cookie的浏览器,才能访问web资源】等等等。

也就是说:当需要限制用户访问某些资源时、在处理请求时提前处理某些资源、服务器响应的内容对其进行处理再返回、我们就是用过滤器来完成的!

二、过滤器的一般用途

1.解决中文乱码问题

只要在过滤器中指定了编码,可以使全站的Web资源都是使用该编码,并且重用性是非常理想的!

public class CharacterEncodingFilter implements Filter {

@Override

public void destroy() {

// TODO Auto-generated method stub

}

@Override

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

throws IOException, ServletException {

request.setCharacterEncoding("utf-8");

chain.doFilter(request, response);

}

@Override

public void init(FilterConfig arg0) throws ServletException {

// TODO Auto-generated method stub

}

}

web.xml配置:

CharacterEncodingFilter

com.entor.filter.CharacterEncodingFilter

CharacterEncodingFilter

/*

2.过滤器 API

只要Java类实现了Filter接口就可以称为过滤器!Filter接口的方法也十分简单:

a8c73d1bbd8a

其中init()和destory()方法就不用多说了,他俩跟Servlet是一样的。只有在Web服务器加载和销毁的时候被执行,只会被执行一次!

值得注意的是doFilter()方法,它有三个参数(ServletRequest,ServletResponse,FilterChain),从前两个参数我们可以发现:过滤器可以完成任何协议的过滤操作!

a8c73d1bbd8a

FilterChain是一个接口,里面又定义了doFilter()方法。这究竟是怎么回事啊??????

我们可以这样理解:过滤器不单单只有一个,那么我们怎么管理这些过滤器呢?在Java中就使用了链式结构。把所有的过滤器都放在FilterChain里边,如果符合条件,就执行下一个过滤器(如果没有过滤器了,就执行目标资源)。

上面的话好像有点拗口,我们可以想象生活的例子:现在我想在茶杯上能过滤出石头和茶叶出来。石头在一层,茶叶在一层。所以茶杯的过滤装置应该有两层滤网。这个过滤装置就是FilterChain,过滤石头的滤网和过滤茶叶的滤网就是Filter。在石头滤网中,茶叶是属于下一层的,就把茶叶放行,让茶叶的滤网过滤茶叶。过滤完茶叶了,剩下的就是茶(茶就可以比喻成我们的目标资源)

三、快速入门

写一个简单的过滤器

实现Filter接口的Java类就被称作为过滤器

public class FilterDemo1 implements Filter {

public void destroy() {

}

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

//执行这一句,说明放行(让下一个过滤器执行,如果没有过滤器了,就执行执行目标资源)

chain.doFilter(req, resp);

}

public void init(FilterConfig config) throws ServletException {

}

}

1.filter部署

过滤器和Servlet是一样的,需要部署到Web服务器上的。

第一种方式:在web.xml文件中配置

FilterDemo1

FilterDemo1

word_file

/WEB-INF/word.txt

FilterDemo1

/*

用于注册过滤器

用于为过滤器指定一个名字,该元素的内容不能为空。

元素用于指定过滤器的完整的限定类名。

元素用于为过滤器指定初始化参数,它的子元素

元素用于设置一个Filter 所负责拦截的资源。

子元素用于设置filter的注册名称。该值必须存在

设置 filter 所拦截的请求路径(过滤器关联的URL样式)

第二种方式:通过注解配置

//@Component//无需添加此注解,在启动类添加@ServletComponentScan注解后,会自动将带有@WebFilter的注解进行注入!

@WebFilter(urlPatterns = "/lvjia/carbodyad/api/*", filterName = "rest0PubFilter")

@Order(1)//指定过滤器的执行顺序,值越大越靠后执行

public class Rest0PubFilter implements Filter {

@Override

public void init(FilterConfig filterConfig) {//初始化过滤器

System.out.println("getFilterName:"+filterConfig.getFilterName());//返回元素的设置值。

System.out.println("getServletContext:"+filterConfig.getServletContext());//返回FilterConfig对象中所包装的ServletContext对象的引用。

System.out.println("getInitParameter:"+filterConfig.getInitParameter("cacheTimeout"));//用于返回在web.xml文件中为Filter所设置的某个名称的初始化的参数值

System.out.println("getInitParameterNames:"+filterConfig.getInitParameterNames());//返回一个Enumeration集合对象。

}

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,

FilterChain filterChain) throws IOException, ServletException {

if(false){

response.sendRedirect("http://localhost:8081/demo/test/login");//重定向

}

filterChain.doFilter(servletRequest, servletResponse);//doFilter将请求转发给过滤器链下一个filter , 如果没有filter那就是你请求的资源

}

@Override

public void destroy() {

}

}

@SpringBootApplication

@ServletComponentScan //Servlet、Filter、Listener 可以直接通过 @WebServlet、@WebFilter、@WebListener 注解自动注册,无需其他代码。

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

}

@WebFilter常用属性

属性

类型

是否必需

说明

asyncSupported

boolean

指定Filter是否支持异步模式

dispatcherTypes

DispatcherType[]

指定Filter对哪种方式的请求进行过滤。支持的属性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST;默认过滤所有方式的请求

filterName

String

Filter名称

initParams

WebInitParam[]

配置参数

displayName

String

Filter显示名

servletNames

String[]

指定对哪些Servlet进行过滤

urlPatterns/value

String[]

两个属性作用相同,指定拦截的路径

过滤器的urlPatterns的过滤路径规则:

全路径匹配: /abc/myServlet1.do

部分路径匹配: /abc/*

通配符匹配 :/*

后缀名匹配 :*.do (注意:前面不加/)

2.过滤器的执行顺序

上面已经说过了,过滤器的doFilter()方法是极其重要的,FilterChain接口是代表着所有的Filter,FilterChain中的doFilter()方法决定着是否放行下一个过滤器执行(如果没有过滤器了,就执行目标资源)。

四、Filter简单应用

filter的三种典型应用:

可以在filter中根据条件决定是否调用chain.doFilter(request, response)方法,即是否让目标资源执行

在让目标资源执行之前,可以对request\response作预处理,再让目标资源执行

在目标资源执行之后,可以捕获目标资源的执行结果,从而实现一些特殊的功能

1.禁止浏览器缓存所有动态页面

public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {

//让Web资源不缓存,很简单,设置http中response的请求头即可了!

//我们使用的是http协议,ServletResponse并没有能够设置请求头的方法,所以要强转成HttpServletRequest

//一般我们写Filter都会把他俩强转成Http类型的

HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) resp;

response.setDateHeader("Expires", -1);

response.setHeader("Cache-Control", "no-cache");

response.setHeader("Pragma", "no-cache");

//放行目标资源的response已经设置成不缓存的了

chain.doFilter(request, response);

}

没有过滤之前,响应头是这样的:

a8c73d1bbd8a

过滤之后,响应头是这样的:

a8c73d1bbd8a

2.实现自动登陆

实体:

private String username ;

private String password;

public User() {

}

public User(String username, String password) {

this.username = username;

this.password = password;

}

//各种setter和getter

集合模拟数据库

public class UserDB {

private static List users = new ArrayList<>();

static {

users.add(new User("aaa", "123"));

users.add(new User("bbb", "123"));

users.add(new User("ccc", "123"));

}

public static List getUsers() {

return users;

}

public static void setUsers(List users) {

UserDB.users = users;

}

}

开发dao

public User find(String username, String password) {

List userList = UserDB.getUsers();

//遍历List集合,看看有没有对应的username和password

for (User user : userList) {

if (user.getUsername().equals(username) && user.getPassword().equals(password)) {

return user;

}

}

return null;

}

登陆界面

用户名

密码

10分钟

30分钟

1小时

处理登陆的Servlet

//得到客户端发送过来的数据

String username = request.getParameter("username");

String password = request.getParameter("password");

UserDao userDao = new UserDao();

User user = userDao.find(username, password);

if (user == null) {

request.setAttribute("message", "用户名或密码是错的!");

request.getRequestDispatcher("/message.jsp").forward(request, response);

}

//如果不是为空,那么在session中保存一个属性

request.getSession().setAttribute("user", user);

request.setAttribute("message", "恭喜你,已经登陆了!");

//如果想要用户关闭了浏览器,还能登陆,就必须要用到Cookie技术了

Cookie cookie = new Cookie("autoLogin", user.getUsername() + "." + user.getPassword());

//设置Cookie的最大声明周期为用户指定的

cookie.setMaxAge(Integer.parseInt(request.getParameter("time")) * 60);

//把Cookie返回给浏览器

response.addCookie(cookie);

//跳转到提示页面

request.getRequestDispatcher("/message.jsp").forward(request, response);

过滤器

HttpServletResponse response = (HttpServletResponse) resp;

HttpServletRequest request = (HttpServletRequest) req;

//如果用户没有关闭浏览器,就不需要Cookie做拼接登陆了

if (request.getSession().getAttribute("user") != null) {

chain.doFilter(request, response);

return;

}

//用户关闭了浏览器,session的值就获取不到了。所以要通过Cookie来自动登陆

Cookie[] cookies = request.getCookies();

String value = null;

for (int i = 0; cookies != null && i < cookies.length; i++) {

if (cookies[i].getName().equals("autoLogin")) {

value = cookies[i].getValue();

}

}

//得到Cookie的用户名和密码

if (value != null) {

String username = value.split("\\.")[0];

String password = value.split("\\.")[1];

UserDao userDao = new UserDao();

User user = userDao.find(username, password);

if (user != null) {

request.getSession().setAttribute("user", user);

}

}

chain.doFilter(request, response);

效果:

a8c73d1bbd8a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的Java代理程序,它将所有传入的流量转发到指定的目标主机和端口,并计算传输的字节数。 ```java import java.io.*; import java.net.*; public class ProxyServer { public static void main(String[] args) throws IOException { int localPort = 8888; String remoteHost = "example.com"; int remotePort = 80; ServerSocket serverSocket = new ServerSocket(localPort); System.out.println("Proxy server listening on port " + localPort); while (true) { Socket clientSocket = serverSocket.accept(); System.out.println("Client connected from " + clientSocket.getRemoteSocketAddress()); Socket serverSocket1 = new Socket(remoteHost, remotePort); System.out.println("Connected to remote server " + remoteHost + ":" + remotePort); new Thread(() -> { try { InputStream clientIn = clientSocket.getInputStream(); OutputStream clientOut = clientSocket.getOutputStream(); InputStream serverIn = serverSocket1.getInputStream(); OutputStream serverOut = serverSocket1.getOutputStream(); byte[] buffer = new byte[1024]; int bytesRead; long totalBytes = 0; while ((bytesRead = clientIn.read(buffer)) != -1) { serverOut.write(buffer, 0, bytesRead); totalBytes += bytesRead; } clientSocket.shutdownInput(); serverSocket1.shutdownOutput(); while ((bytesRead = serverIn.read(buffer)) != -1) { clientOut.write(buffer, 0, bytesRead); totalBytes += bytesRead; } clientSocket.shutdownOutput(); serverSocket1.shutdownInput(); clientSocket.close(); serverSocket1.close(); System.out.println("Transferred " + totalBytes + " bytes"); } catch (IOException e) { e.printStackTrace(); } }).start(); } } } ``` 在上面的代码中,我们首先创建一个ServerSocket来侦听传入的连接。一旦有一个客户端连接,我们就创建一个到目标主机和端口的Socket。然后,我们使用两个线程来读取和写入每个连接的数据。在每个线程中,我们使用一个字节数组缓冲区来读取和写入数据,并计算传输的字节数。最后,我们关闭所有连接并打印传输的字节数。 请注意,上面的代码只是一个简单的代理,它没有进行任何身份验证或安全性检查。在实际应用中,您应该根据需要添加这些功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值