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
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 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 注解形式声明
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所支持的常用属性
属性名 | 类型 | 是否必需 | 说明 |
---|---|---|---|
filterName | String | 否 | 用于指定该Filter的名称,默认为类名 |
urlPatterns/value | String[] | 是 | 用于指定该Filter所拦截的URL, 两个属性相同但不能同时使用 |
servletNames | String[] | 否 | 用于指定该Filter对哪些Servlet执行过滤,可指定多个Servlet的名称,值是@WebServlet中的name属性的取值或web.xml中<servlet-name> 的取值 |
dispatcherTypes | DispatcherType | 否 | 用于指定该Filter对哪种模式的请求进行过滤,支持REQUEST、FORWARD、INCLUDE、ERROR、ASYNC这5个值的任意组合,默认值为REQUEST |
initParams | WebInitParam[] | 否 | 用于指定该Filter的一组配置参数 |
asyncSupport | boolean | 否 | 指定该Filter是否支持异步操作模式 |
displayName | String | 否 | 用于指定该Filter的显示名称 |
description | String | 否 | 指定该Filter的描述信息 |
过滤器通过属性urlPatterns/value指定的URL匹配模式来对匹配的请求地址进行拦截。
属性urlPatterns/value指定的URL匹配模式有如下要求:
- URL匹配模式可以是路径匹配,也可以是扩展名匹配。
- 例如,对请求地址“
http://localhost:8080/chapter10/index.jsp
”,路径匹配可以为“/index.jsp”或“/”;扩展名匹配为“.jsp”,但不能是路径匹配和扩展名匹配的混合,例如“/*.jsp”这种写法是错误的。
- 例如,对请求地址“
- URL匹配模式可以是路径匹配,也可以是扩展名匹配。
【示例】使用@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
- 指异步处理的请求才会通过此过滤器,除此之外,该过滤器不会被调用。
- REQUEST
14.5.2 xml配置方式
过滤器的配置除了通过@WebFilter的Annotation方式进行配置外,还可以通过web.xml文件进行配置,特别对于Servlet3.0之前的版本,只能通过web.xml的方式配置。
【示例】在web.xml中配置Filter
<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>
定义的先后顺序执行; - 实例代码
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
<%--
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
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
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服务器获取动态表格时涉及到跨域的问题:编码过程如下
后端项目
添加依赖
<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>
实体类
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
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.73</version>
</dependency>
json转换测试代码
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格式)
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数据的时候报如下异常:
axios.get('http://127.0.0.1:8080/web/user')
.then((res)=>{
this.tableData = res.data
})
.catch(function (error) {
console.log(error);
});
后端的跨域解决方案:在响应头中添加
使用FIlter的形式修改response的头信心,添加跨域字段
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项目的跨域解决方案:
proxyTable: { // proxy all requests starting with /api to jsonplaceholder
'/api': {
target: 'http://127.0.0.1:8080/web',
changeOrigin: true,
pathRewrite: {
'^/api': ''
},
}
}
