Morecoin mysql MongoDB 物联网项目 Java开发手册 reflection vue路由 vue添加class 相亲网站源码 网赚教程下载 jquery循环遍历 jq去空格 jquery绑定事件的方法 mac安装hadoop 数据库学习 安装mysql python读文件 java案例 java重载和重写 java学习平台 java学习流程 linux如何安装 corelpainter 删除数组中的某个元素 脚本软件 蒙文字体 键盘模拟器 福昕阅读器绿色版 七宗罪游戏下载 go程序设计语言 ios删除描述文件 光头强换肤助手 ie拒绝访问 模拟邻居 ps字体描边 su镜像 Linux进程查看 铁血统帅 imm32 cts测试
当前位置: 首页 > 学习教程  > 编程语言

过滤器实现接口请求报文的参数验证和返回报文的获取业务处理

2020/11/4 15:08:59 文章标签:

首先我们通过实现Filter接口来重写里面的init和doFilter方法。 Slf4j WebFilter(urlPatterns "/*",filterName "channelFilter") public class ChannelFilter implements Filter {private SysMachineService sysMachineService;// 要过滤的地址private…

首先我们通过实现Filter接口来重写里面的init和doFilter方法。 

@Slf4j
@WebFilter(urlPatterns = "/*",filterName = "channelFilter")
public class ChannelFilter implements Filter {

    private SysMachineService sysMachineService;

    // 要过滤的地址
    private static final String LOGIN_URI = "/api/";

    @Override
	public void init(FilterConfig filterConfig) throws ServletException {
		ServletContext sc = filterConfig.getServletContext();
		ApplicationContext cxt = WebApplicationContextUtils.getWebApplicationContext(sc);
		BeanHeader beanHeader = new BeanHeader();
		beanHeader.setApplicationContext(cxt);

        // 获取业务处理的service
		this.sysMachineService = BeanHeader.getBean(SysMachineService.class);
		
	}

    @Override
	public void doFilter(ServletRequest servletRequest, ServletResponse         servletResponse, FilterChain chain) {
		HttpServletRequest request = (HttpServletRequest)servletRequest;
		HttpServletResponse response = (HttpServletResponse)servletResponse;
		response.setContentType("text/html;charset=utf-8");
		String requestPath = request.getRequestURI();


        if(requestPath.contains(LOGIN_URI)){
			try{
                // 通过继承HttpServletRequestWrapper类重写他的方法获取请求参数
                RequestWrapper requestWrapper = new RequestWrapper(request,sysMachineService);
                String body = new String(requestWrapper.getBody());
				log.info("RequestBody: {}", body);

                这里就可以处理你获取到请求报文之后做的处理了


                ResponseWrapper responseWrapper = new ResponseWrapper(response);
				chain.doFilter(requestWrapper, responseWrapper);

				// 获取接口响应报文
				String resMsg = "";
				ResponseWriter responseWriter = responseWrapper.getResponseWriter();
				if (responseWriter != null) {
					resMsg = responseWriter.getContent();
					log.info("接口响应报文:" + resMsg);
				}

                这里我们可以处理接口返回结果之后的业务逻辑处理

            }catch (Exception e){
				log.error("异常:", e);
		    } finally {

			} 
        }else{
			chain.doFilter(request, response);
		}   
    }
}

如果过滤器处理之后需要讲结果返回,那可以通过流方式就结果写出去。

private void sendJsonMessage(HttpServletResponse response, Object obj) {
    try {
		response.setContentType("application/json; charset=utf-8");
		PrintWriter writer = response.getWriter();
		writer.print(JSONObject.toJSONString(obj, new SerializerFeature[]{SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat}));
		writer.close();
		response.flushBuffer();
	} catch (Exception e){
		log.error("输出异常:" + e.getMessage());
	}
}

关键代码,我们通过继承HttpServletRequestWrapper类来实现我们在过滤器中读取请求接口时的请求报文;也可以在请求的报文中添加个别参数,比如用户的基础信息,或者其他一些参数,这些参数在调用接口时不需要调用方传参,但是在接口处理业务逻辑时又需要用到这些参数,就可以通过这种来实现。

public class RequestWrapper extends HttpServletRequestWrapper {
	private byte[] body;

	private SysMachineService sysMachineService;

	public RequestWrapper(HttpServletRequest request, SysMachineService sysMachineService) {
		super(request);
		this.sysMachineService = sysMachineService;
		try {
			Map map = getParameterMap();
			if (map.size() > 0) {
				map = detectParameter(map);
				body = JSON.toJSONString(map).getBytes();
			} else {
				// 获取请求接口时的请求报文,通过流读取参数数据,并保存
				body = getByteByStream(request.getInputStream());
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 重写获取流中参数方法
	 */
	@Override
	public ServletInputStream getInputStream() throws IOException {
		final ByteArrayInputStream is = new ByteArrayInputStream(body);
		return new ServletInputStream() {

			@Override
			public boolean isFinished() {
				return false;
			}

			@Override
			public boolean isReady() {
				return false;
			}

			@Override
			public void setReadListener(ReadListener listener) {

			}

			@Override
			public int read() throws IOException {
				return is.read();
			}
		};
	}

	/**
	 * 取出流中的数据,做参数检验后放入body中
	 */
	public byte[] getByteByStream(InputStream is) throws Exception {
		byte[] buffer = new byte[1024];
		int len = 0;
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		//读出流中的数据
		while ((len = is.read(buffer)) != -1) {
			bos.write(buffer, 0, len);
		}
		bos.flush();
		bos.close();
		if (bos.size() > 0) {
			//把数据转成Map形式,遍历进行检测
			String str = bos.toString();
			Map maps = detectParameter((Map) JSON.parse(str));


            // 这里其实就是我们在请求报文中新增加了两个业务参数orgId和tenantId,它们是接口请求时请求报文中没有参数,我们通过过滤器将参数写入到报文中的
			if(maps.containsKey("appKey")) {
				String appKey = maps.get("appKey").toString();
				SysMachine entity = this.sysMachineService.selectSysMachine(appKey);
				maps.put("orgId", entity.getOrgId());
				maps.put("tenantId", entity.getTenantId());
			}

			//保存检测后的数据
			str = JSON.toJSONString(maps);
			return str.getBytes();
		}
		return bos.toByteArray();
	}

	/**
	 * 获取请求报文
	 */
	public Map detectParameter(Map parameterMap) {
		Map map = new HashMap();
		//遍历参数MAP
		for (Object key : parameterMap.keySet()) {
			Object parameter = parameterMap.get(key);
			//判断参数类型,集合和数组遍历拆解检测,检测完存入检测结果集合
			if (parameter instanceof JSONObject) {
				map.put(key, detectParameter((Map) parameter));
			} else if (parameter instanceof JSONArray) {
				JSONArray parameterArray = (JSONArray) parameter;
				for (int i = 0; i < parameterArray.size(); i++) {
					parameterArray.set(i, detectParameter(parameterArray.getJSONObject(i)));
				}
				map.put(key, parameterArray);
			} else {
				map.put(key, parameter);
			}
		}
		return map;
	}

	public byte[] getBody() {
		return this.body;
	}

获取接口返回报文的我们也是通过继承HttpServletResponseWrapper和PrintWriter来重写它们的方法来实现。

public class ResponseWrapper extends HttpServletResponseWrapper {

	private ResponseWriter responseWriter;


	public ResponseWrapper(HttpServletResponse response) {
		super(response);
	}

	@Override
	public PrintWriter getWriter() throws IOException {
		responseWriter = new ResponseWriter(super.getWriter());
		return responseWriter;
	}

	public ResponseWriter getResponseWriter() {
		return responseWriter;
	}
}
public class ResponseWriter extends PrintWriter {

	private StringBuilder buffer;

	public ResponseWriter(Writer out) {
		super(out);
		buffer = new StringBuilder();
	}

	@Override
	public void write(char[] buf, int off, int len) {
		char[] dest = new char[len];
		buffer.append(dest);
	}

	@Override
	public void write(char[] buf) {
		super.write(buf);
	}

	@Override
	public void write(int c) {
		super.write(c);
	}

	@Override
	public void write(String s, int off, int len) {
		super.write(s, off, len);
		buffer.append(s);
	}

	@Override
	public void write(String s) {
		super.write(s);
	}

	public String getContent(){
		return buffer.toString();
	}

}

最后贴上一个获bean的代码

public class BeanHeader implements ApplicationContextAware {
	private static final Logger log = LoggerFactory.getLogger(BeanHeader.class);
	private static ApplicationContext applicationContext;

	public BeanHeader() {
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		BeanHeader.applicationContext = applicationContext;
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public static boolean checkapplicationContext() {
		boolean flag = getApplicationContext() != null;
		if (!flag) {
			log.error("applicaitonContext未注入,实现ApplicationContextAware的类必须被spring管理");
		}

		return flag;
	}

	public static <T> T getBean(String name) {
		return checkapplicationContext() ? (T) getApplicationContext().getBean(name) : null;
	}

	public static <T> T getBean(Class<T> clazz) {
		return checkapplicationContext() ? getApplicationContext().getBean(clazz) : null;
	}

	public static <T> T getBean(String name, Class<T> clazz) {
		return checkapplicationContext() ? getApplicationContext().getBean(name, clazz) : null;
	}

然后我们做个测试

在我们请求的报文中是没有tenantId和orgId这两个参数的,但是打印的日志中我们实现了添加这两个参数;并且我们在过滤器中也成功获取到了接口请求参数,实现了我们的需求。

最近在工作中遇到这样一个需求,所以简单的写一下,有同学遇到同样的需求也可以做个参考。

 

 


本文链接: http://www.dtmao.cc/news_show_350348.shtml

附件下载

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?