Skip to content

14. 过滤器

14.1 介绍

过滤器(Filter)也称之为拦截器,是Servlet 2.3规范新增的功能,在Servlet 2.4规范中得到增强。

Filter是Servlet技术中非常实用的技术,Web开发人员通过Filter技术,可以在用户访问某个Web资源(如:JSP、Servlet、HTML、图片、CSS等)之前,对访问的请求和响应进行拦截,从而实现一些特殊功能。

​ 例如,验证用户访问权限、记录用户操作、对请求进行重新编码、压缩响应信息等。

​ 过滤器所处的位置

过滤器的运行原理:

​ 当用户的请求到达指定的网页之前,可以借助过滤器来改变这些请求的内容,此过程也称为“预处理”;

​ 当执行结果要响应到用户之前,可经过过滤器修改响应输出的内容,此过程称为“后处理”。

一个过滤器的运行过程可以分解为如下几个步骤:

  • Web容器判断接收的请求资源是否有与之匹配的过滤器,如果有,容器将请求交给相应过滤器进行处理;
  • 在过滤器预处理过程中,可以改变请求的内容,或者重新设置请求的报头信息,然后将请求发给目标资源;
  • 目标资源对请求进行处理后作出响应;
  • 容器将响应转发回过滤器;
  • 在过滤器后处理过程中,可以根据需求对响应的内容进行修改;
  • Web容器将响应发送回客户端。

14.2 过滤器链

  • 在一个Web应用中,也可以部署多个过滤器,这些过滤器组成了一个过滤器链。
  • 过滤器链中的每个过滤器负责特定的操作和任务,客户端的请求可以在这些过滤器之间进行传递,直到达到目标资源。
  • 例如,一个由两个Filter所组成的过滤器链的过滤过程:

  • 在客户端的请求响应过程中,并不需要经过所有的过滤器链,而是根据过滤器链中每个过滤器的过滤条件来匹配需要过滤的资源。

14.3 过滤器核心接口

  • 过滤器的实现主要依靠以下核心接口:
    • javax.servlet.Filter接口
    • javax.servlet.FilterConfig接口
    • javax.servlet.FilterChain接口
  • 与开发Servlet需要实现Servlet接口类似,开发Filter要实现javax.servlet.Filter接口,并提供一个公共的不带参数的构造方法。
  • Filter接口的方法及说明
方法说明
init(FilterConfig config)容器在过滤器实例化后调用此方法对过滤器进行初始化,同时向其传递FilterConfig对象,用于获得和Servlet相关的ServletContext对象
doFilter(ServletRequest request,ServletResponse response,FilterChain chain)过滤器的功能实现方法。当用户请求经过时,容器调用此方法对请求和响应进行功能处理。该方法由容器传入三个参数对象,分别用于获取请求对象、响应对象和FilterChain对象,请求和响应对象类型分别为ServletRequest和ServletResponse,并不依赖于具体的协议,FilterChian对象的doFilter(request,response)方法负责将请求传递给下一个过滤器或目标资源
destroy()该方法在过滤器生命周期结束前由Web容器调用,可用于使用资源的释放
  • FilterConfig接口

    • javax.servlet.FilterConfig接口由容器实现,容器将其实例作为参数传入过滤器(Filter)对象的初始化方法init()中,来获取过滤器的初始化参数和Servlet的相关信息。 FilterConfig接口的主要方法及作用
    方法说明
    getFilterName()获取配置信息中指定的过滤器的名字
    getInitParameter(String name)获取配置信息中指定的名为name的过滤器初始化参数值
    getInitParameterNames()获取过滤器的所有初始化参数的名字的枚举集合
    getServletContext()获取Servlet上下文对象
  • FilterChain接口

    • javax.servlet.FilterChain接口由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。
方法说明
doFilter(ServletRequest request,ServletResponse response)该方法将使过滤器链中的下一个过滤器被调用,如果调用该方法的过滤器是链中最后一个过滤器,那么目标资源被调用

14.4 声明周期

过滤器的生命周期分为四个阶段:

  • 加载和实例化
    • Web容器启动时,会根据@WebFilter属性filterName所定义的类名的大小写拼写顺序,或者web.xml中声明的Filter顺序依次实例化Filter。
  • 初始化
    • Web容器调用init(FilterConfig config)方法来初始化过滤器。容器在调用该方法时,向过滤器传递FilterConfig对象。实例化和初始化的操作只会在容器启动时执行,并且只会执行一次。
  • doFilter()方法的执行
    • 当客户端请求目标资源的时候,容器会筛选出符合过滤器映射条件的Filter,并按照@WebFilter属性filterName所定义的类名的大小写拼写顺序,或者web.xml中声明的filter-mapping的顺序依次调用这些过滤器的doFilter()方法。在这个链式调用过程中,可以调用FilterChain对象的doFilter方法将请求传给下一个过滤器(或目标资源),也可以直接向客户端返回响应信息,或者利用请求转发或重定向将请求转向到其它资源。需要注意的是,这个方法的请求和响应参数的类型是ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
  • 销毁
    • Web容器调用destroy()方法指示过滤器的生命周期结束。在这个方法中,可以释放过滤器使用的资源。

14.4 实现过滤器

基于过滤器的核心接口,一个过滤器的开发可以经过下述三个步骤:

  • 创建Filter接口实现类;
  • 编写过滤器的功能代码;
  • 对过滤器进行声明配置

14.4.1 在web.xml中配置

定义了Filter 类 Fitler1

java
package com.neuedu.his.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 项目:      his1215
 * 类名:       Filter1
 * 创建时间:  2020/12/16  11:21
 * 描述 :
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 *
 *
 *
 *
 *
 */
public class Filter1 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter1.init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;
        String uri = req.getRequestURI();

        System.out.println("过滤器 code1 "+uri);
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        System.out.println("Filter1.destroy");
    }
}

上述Filter在web.xml中声明

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_3_1.xsd"
         version="3.1">
  <display-name>Archetype Created Web Application</display-name>
  
  
  <filter>
    <filter-name>Filter1</filter-name>
    <filter-class>com.neuedu.his.filter.Filter1</filter-class>
  </filter>
  
  
  <filter-mapping>
    <filter-name>Filter1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
    
</web-app>

14.4.2 注解形式声明

java
package com.neuedu.his.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 项目:      his1215
 * 类名:       Filter1
 * 创建时间:  2020/12/16  11:21
 * 描述 :
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 *
 *
 *
 *
 *
 */
@WebFilter(filterName="Filter2",urlPatterns = "/disease")
public class Filter2 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter2.init");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器 code2 ");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {
        System.out.println("Filter1.destroy");
    }
}

14.5 过滤器声明配置

14.5.1 注解的形式配置

在Servlet3.0以上版本中,既可以使用@WebFilter形式的Annotation对Filter进行声明配置,也可以在web.xml文件中进行配置。

@WebFilter所支持的常用属性

属性名类型是否必需说明
filterNameString用于指定该Filter的名称,默认为类名
urlPatterns/valueString[]用于指定该Filter所拦截的URL, 两个属性相同但不能同时使用
servletNamesString[]用于指定该Filter对哪些Servlet执行过滤,可指定多个Servlet的名称,值是@WebServlet中的name属性的取值或web.xml中<servlet-name>的取值
dispatcherTypesDispatcherType用于指定该Filter对哪种模式的请求进行过滤,支持REQUEST、FORWARD、INCLUDE、ERROR、ASYNC这5个值的任意组合,默认值为REQUEST
initParamsWebInitParam[]用于指定该Filter的一组配置参数
asyncSupportboolean指定该Filter是否支持异步操作模式
displayNameString用于指定该Filter的显示名称
descriptionString指定该Filter的描述信息
  • 过滤器通过属性urlPatterns/value指定的URL匹配模式来对匹配的请求地址进行拦截。

  • 属性urlPatterns/value指定的URL匹配模式有如下要求:

    • URL匹配模式可以是路径匹配,也可以是扩展名匹配。
      • 例如,对请求地址“http://localhost:8080/chapter10/index.jsp”,路径匹配可以为“/index.jsp”或“/”;扩展名匹配为“.jsp”,但不能是路径匹配和扩展名匹配的混合,例如“/*.jsp”这种写法是错误的。
  • 【示例】使用@WebFilter配置Filter

    java
    @WebFilter(description = "Filter 示例", displayName = "TestFilter",
    	filterName = "TestFilter", 
    	urlPatterns = { "*.jsp" }, servletNames = { "TestServlet" }, 
    	initParams = { @WebInitParam(name = "CharacterEncoding", value = "UTF-8") }, 
    	dispatcherTypes = { DispatcherType.REQUEST }, 
    	asyncSupported = false
    	)
    • 上述示例配置表示,在过滤器初始化时向过滤器传递初始化参数“CharacterEncoding”,值为“UTF-8”; 对所有的JSP页面请求和配置名称为TestServlet的Servlet请求,在请求模式为REQUEST时进行过滤;不使用异步模式;过滤器名称和显示名称均为“TestFilter”,描述信息为“Filter示例”。
  • @WebFilter的属性dispatcherTypes的五个取值对应的转发模式的含义如下所示:

    • REQUEST
      • 当用户直接对网页做出请求的动作时,才会通过此Filter。而例如请求转发发出的请求则不会通过此Filter。
    • FORWARD
      • 指由RequestDispatcher对象的forward()方法发出的请求才会通过此Filter,除此之外,该过滤器不会被调用。
    • INCLUDE
      • 指由RequestDispatcher对象的include()方法发出的请求才会通过此Filter,除此之为,该过滤器不会被调用。
    • ERROR
      • 如若在某个页面使用page指令指定了error属性,那么当此页面出现异常跳转到异常处理页面时才会经过此Filter,除此之外,该过滤器不会被调用。
    • ASYNC
      • 指异步处理的请求才会通过此过滤器,除此之外,该过滤器不会被调用。

14.5.2 xml配置方式

​ 过滤器的配置除了通过@WebFilter的Annotation方式进行配置外,还可以通过web.xml文件进行配置,特别对于Servlet3.0之前的版本,只能通过web.xml的方式配置。

【示例】在web.xml中配置Filter

xml
<filter>
		<description>Filter 示例</description>
		<display-name>TestFilter</display-name>
		<filter-name>TestFilter</filter-name>
		<filter-class>com.neuedu.filter.TestFilter</filter-class>
		<async-supported>false</async-supported>
		<init-param>
			<param-name>CharacterEncoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>TestFilter</filter-name>
		<url-pattern>*.jsp</url-pattern>
		<servlet-name>TestServlet</servlet-name>
		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>

14.6 过滤器应用

在Web开发中,Filter是非常重要而且实用的技术,其应用非常广泛,如下为几种常见的使用情况:

  • 做统一的认证处理;
  • 对用户的请求进行检查和更精确的记录;
  • 监视或对用户所传递的参数做前置处理,例如:防止数据注入攻击;
  • 改变图像文件的格式;
  • 对请求和响应进行编码;
  • 对响应做压缩处理;
  • 对XML的输出使用XSLT来转换。

14.6.1 设置请求编码

在前面章节的介绍中,对POST请求参数的乱码问题通常采用如下代码进行设置:

  • request.setCharacterEncoding("UTF-8");
  • 使用这种方法有一个缺点:必须对每一个获得请求参数的程序都要加入上述程序代码。这种做法显然增加了重复的工作量,此时使用过滤器便可轻松予以解决。

需要注意的是,只有在最初使用请求对象的程序前进行编码设置,才会对后续使用程序起作用,因此,该过滤器在执行顺序上应该保证早于其它过滤器的执行。

这种情况下,可以采用以下三种方式解决:

  • 方式一:完全基于Annotation的过滤器方式的配置,可以通过设置filterName按照过滤器的名称首字母顺序执行;
  • 方式二:完全使用web.xml的方式对过滤器链配置,相同映射条件下,按照<filter-mapping>定义的先后顺序执行;
  • 实例代码
java
package com.neuedu.his.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 项目:      his1215
 * 类名:       ${NAME}
 * 创建时间:  2020/12/16  13:35
 * 描述 :     ${dc}
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 */
@WebFilter(filterName = "CharsetFilter", urlPatterns = "/*",
        initParams = {
                @WebInitParam(name = "charset", value = "UTF-8")
        }
)
public class CharsetFilter implements Filter {

    private String charset;

    public void init(FilterConfig config) throws ServletException {
        charset = config.getInitParameter("charset");
    }

    public void destroy() {
    }

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

        req.setCharacterEncoding(charset);  //post请求
        resp.setCharacterEncoding(charset);

        chain.doFilter(req, resp);
    }


}

14.6.2 控制用户访问权限

在Web应用中,有很多操作是需要用户具有相关的操作权限才可进行访问的,例如:用户个人中心、网站后台管理、同一系统不同角色的访问。这些应用的权限控制可以在具体的访问资源中单独设置,也可以使用过滤器统一设置,显然后者具有更高的效率和可维护性。

该实例的实现思路如下:

  • 设置较为全面的请求拦截映射地址,但对于用户登陆页面及处理登录操作的Servlet不能进行访问限制,可用初始化参数灵活指定相关地址。

  • 通过判断会话对象中是否存在用户登陆成功时设置的域属性,来决定用户是否有访问的权限。

登录页面 login.jsp

html
<%--
  Created by IntelliJ IDEA.
  User: root
  Date: 2020/12/16
  Time: 14:26
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
    <style>
        .container {


            position: absolute;

            top: 260px;
            left: 500px;
            width: 400px;
            height: 260px;
            border: solid 1px blue;
            /*background-color: cadetblue;*/
            border-radius: 20px  ;
            box-shadow:0 0 90px #358d37;
        }

        form div{
            margin: 10px;
            margin-bottom: 30px;
        }


        input[type='text'],  input[type='password']{
            width: 200px;
            height: 30px;
            border-radius: 6px;
        }
        input[type='button']{

            width: 90px;
            height: 32px;
            background-color: #40AFFE;
            border-radius: 6px;
            border: none;
            margin-left: 80px;
        }

        span{
            display: inline-block;
            width: 60px ;
        }


    </style>
    <script src="http://libs.baidu.com/jquery/1.11.1/jquery.min.js"></script>
<script>


    $(function(){

        $("#btnLogin").click(function(){

            $.ajax('${pageContext.request.contextPath}/login',{
                type:'post',
                data:{
                    username:$("#username").val(),
                    password:$("#password").val()
                },
                dataType:'json',
                success:function(data){
                    if(data.success){
                        alert('登录成功');
                        window.location.href ="disease"
                    }else{
                        alert(data.msg)
                    }
                }

            })
        })
    })

</script>
</head>
<body>


<div class="container">
    <div> <h3 align="center">欢迎使用xxxx系统</h3></div>
    <form>
        <div><span>用户名:</span> <span><input type="text" id="username"/> </span>   </div>


        <div><span>密码:   </span> <span><input type="password" id="password"/> </span>   </div>
        <div><input  type="button" id="btnLogin" value="登录"/> </div>

    </form>


</div>


</body>
</html>

登录的控制器 LoginController

java
package com.neuedu.his.controller;

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;

/**
 * 项目:      his1215
 * 类名:       LoginController
 * 创建时间:  2020/12/16  14:33
 * 描述 :     登录逻辑
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 */
@WebServlet(name="Login",urlPatterns = "/login")
public class LoginController extends HttpServlet {


    /**
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        /**
         * admin  123456
         *
         * http://127.0.0.1:8080/web/login?username=abc&password=123456
         */

        String username = req.getParameter("username");
        String password = req.getParameter("password");
        HttpSession session = req.getSession();

        boolean success = false;
        String msg = "";
        if("admin".equals(username)
          && "123456".equals(password)){
            session.setAttribute("username",username);
            success = true;
        }else{
            msg = "用户名或密码不正确";
        }
        String info = String.format("{\"success\":%s, \"msg\":\"%s\"}",
                String.valueOf(success),
                msg
        );

        PrintWriter out = resp.getWriter();

        out.println(info);
        out.flush();
        out.close();
        

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

拦截器LoginFilter

java
package com.neuedu.his.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * 项目:      his1215
 * 类名:       ${NAME}
 * 创建时间:  2020/12/16  15:47
 * 描述 :     ${dc}
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 */
@WebFilter(filterName = "LoginFilter",urlPatterns = "/*")
public class LoginFilter 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;

        /**
         * 排除的路径
         *      js css png jpg html
         *
         *      /login   index.jsp
         *
         */


        boolean pass = false;

        //判断是否忽略的扩展名js png 或者是地址 /login /login.jsp
        if( isPassUrl(request)){
            pass = true;
        }else{
            //验证是否登录

            HttpSession session = request.getSession();
            String username = (String) session.getAttribute("username");

            if(username != null &&  !"".equals(username)){
                pass = true;
            }
            
        }

        if(pass){
            chain.doFilter(req, resp);
        }else{
            //跳转到登录页面
            response.sendRedirect(((HttpServletRequest) req).getContextPath()+"/login.jsp");
        }


    }

    private boolean isPassUrl(HttpServletRequest request) {
        String[] exts = {"js","css","png","jpg","jpeg"};
        String[] urls = {"/login","/login.jsp"};
        String uri = request.getRequestURI();
        uri = uri.substring(uri.lastIndexOf("/"));

        String ext = "";
        if(uri.indexOf(".") != -1 ){
            ext = uri.substring(uri.indexOf(".")+1);
        }


        //判断是否 忽略的扩展名
        for (String s : exts) {
            if(ext.equals(s)){
                return true;
            }
        }


        for (String url : urls) {
            if(url.equals(uri)){
                return true;
            }
        }

        return false;

    }

    public void init(FilterConfig config) throws ServletException {

    }

}

多个拦截器的优先级

  • web.xml的形式,由配置filter-mapping的顺序决定,优先配置优先级越大
  • @WebFilter的形式,按照类名的自然语言排序

14.6.3 后端支持跨域请求

同源策略是一个重要的安全策略,它用于限制一个origin的文档或者它加载的脚本如何能与另一个源的资源进行交互。它能帮助阻隔恶意文档,减少可能被攻击的媒介。

浏览器的同源策略参考 网址https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy

vuejs项目请求 javaweb服务器获取动态表格时涉及到跨域的问题:编码过程如下

后端项目

添加依赖

xml
<dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.0.1</version>
      <!--作用域  provided  参与编译,运行时抛弃 -->
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.73</version>
    </dependency>

实体类

java
package com.neuedu.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * 项目:      CrossDomain
 * 类名:       User
 * 创建时间:  2020/12/17  13:46
 * 描述 :
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    private Integer id;
    private String name;
    private String address;
    private Date date;

}

14.6.3.1访问Controller获取动态表格的json数据

在将List集合转换成json字符串时手动拼接字符串会比较繁琐,可以使用json类库,如fastjson、jsckson等

对象转json字符串

使用类库,fastjson

xml
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.73</version>
    </dependency>

json转换测试代码

java
public class JsonTest {



    @Test
    public void test(){
        List userList = new ArrayList();
        userList.add(new User(1,"王小虎1","1上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(2,"王小虎2","2上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(3,"王小虎3","3上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(4,"王小虎4","4上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(5,"王小虎5","5上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(6,"王小虎6","6上海市普陀区金沙江路 1518 弄",new Date()));


        String json = JSON.toJSONString(userList,   SerializerFeature.WriteDateUseDateFormat    );


        System.out.println(json);

    }


}

编写Controller代码用于提供 用户列表(json格式)

java
package com.neuedu.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.neuedu.entity.User;

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;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 项目:      CrossDomain
 * 类名:       UserController
 * 创建时间:  2020/12/17  13:48
 * 描述 :     用户的控制器
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 *
 *
 * http://127.0.0.1:8080/web/user
 */
@WebServlet(name="UserController" ,urlPatterns = "/user")
public class UserController extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        List userList = new ArrayList();
        userList.add(new User(1,"王小虎1","1上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(2,"王小虎2","2上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(3,"王小虎3","3上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(4,"王小虎4","4上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(5,"王小虎5","5上海市普陀区金沙江路 1518 弄",new Date()));
        userList.add(new User(6,"王小虎6","6上海市普陀区金沙江路 1518 弄",new Date()));

        String json = JSON.toJSONString(userList,   SerializerFeature.WriteDateUseDateFormat    );


        resp.setContentType("application/json");
        resp.setCharacterEncoding("utf-8");
        PrintWriter out = resp.getWriter();
        out.write(json);
        out.flush();
        out.close();

    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

访问 http://127.0.0.1:8080/web/user 可以看到如下结果:

前端项目使用axios访问json数据的时候报如下异常:

js
axios.get('http://127.0.0.1:8080/web/user')
			 .then((res)=>{
				 this.tableData = res.data
			 })
			  .catch(function (error) {
			    console.log(error);
			  });

后端的跨域解决方案:在响应头中添加

使用FIlter的形式修改response的头信心,添加跨域字段

java
package com.neuedu.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 项目:      CrossDomain
 * 类名:       CrossFilter
 * 创建时间:  2020/12/17  14:39
 * 描述 :     允许跨域访问的拦截器
 * 作者 :     张金山
 * QQ :     314649444
 * Site:      https://jshand.gitee.io
 */
@WebFilter(urlPatterns = "/*")
public class CrossFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse resp = (HttpServletResponse) response;
        resp.addHeader("Access-Control-Allow-Origin","*");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {

    }
}

其他跨域解决方案请参考 博客

vue-cli项目的跨域解决方案:

js
proxyTable: { // proxy all requests starting with /api to jsonplaceholder 
		'/api': {
			target: 'http://127.0.0.1:8080/web',
			changeOrigin: true,
			pathRewrite: {
				'^/api': ''
			},
		}
	}

Released under the MIT License.