Java实现mock server
Java实现mock有两种方式:
-
servlet的Filter功能
-
spring的HandlerInterceptor
Filter和HandlerInterceptor的区别:
这两者在功能方面很类似,但是在具体技术实现方面,差距还是比较大的。过滤器和拦截器都属于面向切面编程的具体实现。而两者的主要区别包括以下几个方面:
Filter是基于函数回调(doFilter()方法)的,而Interceptor则是基于Java反射的(AOP思想)。
Filter是依赖于Servlet容器,属于Servlet规范的一部分,而拦截器则是独立存在的,可以在任何情况下使用。
Filter的执行由Servlet容器回调完成,而拦截器通常通过动态代理的方式来执行。
Filter的生命周期由Servlet容器管理,而拦截器则可以通过IoC容器来管理,因此可以通过注入等方式来获取其他Bean的实例,因此使用会更方便。
Filter
Filter可以认为是Servlet的一种“加强版”,它主要用于对用户请求进行预处理,也可以对HttpServletResponse进行后处理,是个典型的处理链。Filter也可以对用户请求生成响应,这一点与Servlet相同,但实际上很少会使用Filter向用户请求生成响应。使用Filter完整的流程是:
Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
Filter有如下几个用处:
-
在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
-
根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
-
在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
-
根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
Filter有如下几个种类:
-
用户授权的Filter:Filter负责检查用户请求,根据请求过滤用户非法请求。
-
日志Filter:详细记录某些特殊的用户请求。
-
负责解码的Filter:包括对非标准编码的请求解码。
-
能改变XML内容的XSLT Filter等。
-
Filter可以负责拦截多个请求或响应;一个请求或响应也可以被多个Filter拦截。
创建Filter必须实现javax.servlet.Filter接口,在该接口中定义了如下三个方法:
-
void init(FilterConfig config):用于完成Filter的初始化。
-
void destory():用于Filter销毁前,完成某些资源的回收。
-
void doFilter(ServletRequest request,ServletResponse response,FilterChain chain):实现过滤功能,该方法就是对每个请求及响应增加的额外处理。该方法可以实现对用户请求进行预处理(ServletRequest request),也可实现对服务器响应进行后处理(ServletResponse response)—它们的分界线为是否调用了chain.doFilter(),执行该方法之前,即对用户请求进行预处理;执行该方法之后,即对服务器响应进行后处理。
实际代码如下:
自定义filter
@WebFilter(urlPatterns = "/mock/*",filterName = "fmsMockFilter") @Slf4j public class MockFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request=(HttpServletRequest) servletRequest; HttpServletResponse response=(HttpServletResponse) servletResponse; log.info("对"+request.getRequestURL()+"进行mock"); // 设置跨域 setCorsHeader(request,response); // mock的主要逻辑 handle(request,response); } @Override public void destroy() { } /** * 设置filter跨域 * @param request * @param response */ private static void setCorsHeader(HttpServletRequest request, HttpServletResponse response) { // 域 response.setHeader("Access-Control-Allow-Origin", StringUtils.isNotBlank(request.getHeader("Origin"))?request.getHeader("Origin"):"*"); // credentials response.setHeader("Access-Control-Allow-Credentials", "true"); // method response.setHeader("Access-Control-Allow-Methods", "*"); // age response.setHeader("Access-Control-Max-Age", "3600"); // header response.setHeader("Access-Control-Allow-Headers", StringUtils.isNotBlank(request.getHeader("Access-Control-Allow-Headers"))?request.getHeader("Access-Control-Allow-Headers"):"*"); } private static void handle(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setCharacterEncoding("utf-8"); response.setContentType(ContentType.APPLICATION_JSON.toString()); //处理response //todo //1、通过req的url,查询存储的mock response、header、status、 //2、设置response的属性为1中mock response的属性 response.setStatus(200); JSONObject content=new JSONObject(); content.put("mock_k1","mock_v1"); content.put("mock_k2","mock_v2"); // 设置response的content @Cleanup PrintWriter writer = response.getWriter(); writer.print(content.toJSONString()); writer.flush(); } }
注册filter的方式有两种:
-
实现Filter的类不使用
@WebFilter
,需要手动注册filter,代码如下@Configuration public class FilterConfig { @Bean public FilterRegistrationBean registFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MockFilter()); registration.addUrlPatterns("/mock/*"); registration.setName("fmsMockFilter"); registration.setOrder(1); return registration; } }
-
实现Filter的类使用
@WebFilter
,需要在启动类上使用@ServletComponentScan
扫包,代码如下@SpringBootApplication @ServletComponentScan("com.mock.config") public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }
HandlerInterceptor
1、对于管理系统,通常都需要进行身份认证、权限控制、日志、统计等操作,比如不能让用户直接就进到了后台主页,必须先经过登陆页进行登陆。
2、Spring MVC 的 org.springframework.web.servlet.HandlerInterceptor 拦截器,可以对任何的后台请求进行拦截,Spring Boot 2.x 版本中默认还会对所有静态资源一并拦截。
3、HandlerInterceptor 拦截器接口一共有3个方法:
-
preHandle 拦截处理程序的执行:在 HandlerMapping 确定适当的处理程序对象之后,且在 HandlerAdapter 调用处理程序之前调用。
-
postHandle 拦截处理程序的执行:在 HandlerAdapter 实际调用处理程序之后,且在 DispatcherServlet 呈现视图之前调用。
-
afterCompletion 请求处理完成后(即呈现视图后)回调,将在处理程序执行的任何结果上调用,从而允许适当的资源清理。
-
注意:仅当此拦截器的 preHandle 方法已成功完成并返回 true 时才会调用! 与 postHandle 方法一样,该方法将按相反顺序在链中的每个拦截器上调用,因此第一个拦截器将是最后一个被调用的拦截器。
-
方法返回值:
-
true - 执行链可以执行下一个拦截器或handler本身。最终请求到controller
-
false - 拦截器已经处理了相应。请求被拦截,不会请求到controller
自定义拦截器
// 自定义拦截器,需要实现 HandlerInterceptor public class MockHandlerInterceptor implements HandlerInterceptor{ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 设置跨域,statuscode。headers setCorsHeader(request,response); response.setStatus(200); response.setContentType(ContentType.APPLICATION_JSON.toString()); // 设置响应内容 JSONObject content=new JSONObject(); content.put("mock_k1","mock_v1"); content.put("mock_k2","mock_v2"); @Cleanup PrintWriter writer = response.getWriter(); writer.print(content.toJSONString()); writer.flush(); //false 拦截请求,不请求到controller return false; } private static void setCorsHeader(HttpServletRequest request, HttpServletResponse response) { // 域 response.setHeader("Access-Control-Allow-Origin", StringUtils.isNotBlank(request.getHeader("Origin"))?request.getHeader("Origin"):"*"); // credentials response.setHeader("Access-Control-Allow-Credentials", "true"); // method response.setHeader("Access-Control-Allow-Methods", "*"); // age response.setHeader("Access-Control-Max-Age", "3600"); // header response.setHeader("Access-Control-Allow-Headers", StringUtils.isNotBlank(request.getHeader("Access-Control-Allow-Headers"))?request.getHeader("Access-Control-Allow-Headers"):"*"); } }
注册拦截器
@Configuration // 注册拦截器,实现 WebMvcConfigurer public class WebConfig implements WebMvcConfigurer { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new MockHandlerInterceptor()) .addPathPatterns("/mock/**"); // ** 表示拦截以 /mock 开头的所有请求 } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具